From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3639 invoked by alias); 23 Oct 2010 20:58:43 -0000 Received: (qmail 3618 invoked by uid 22791); 23 Oct 2010 20:58:37 -0000 X-SWARE-Spam-Status: No, hits=-5.3 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_CX,TW_RG,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 23 Oct 2010 20:58:26 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o9NKwO1B026175 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sat, 23 Oct 2010 16:58:25 -0400 Received: from tutu.torimasen.com.redhat.com (ovpn-113-34.phx2.redhat.com [10.3.113.34]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id o9NKwMHs001569; Sat, 23 Oct 2010 16:58:23 -0400 From: Dodji Seketeli To: Jason Merrill Cc: Paolo Carlini , "H.J. Lu" , GCC Patches Subject: Re: Require canonical type comparison for typedefs again. References: <4C9673B7.5010505@oracle.com> <4C97C9E5.2090907@redhat.com> <4C9E863C.30208@redhat.com> <4CA1F184.4080708@redhat.com> <4CA397D0.3000100@redhat.com> <288BF79E-5BED-4568-BD82-71E9EA181C07@oracle.com> <4CBF0189.7090701@redhat.com> <4CBF58DE.2000001@redhat.com> <4CBF80E3.8080206@redhat.com> X-URL: http://www.seketeli.net/~dodji Date: Sat, 23 Oct 2010 22:46:00 -0000 In-Reply-To: <4CBF80E3.8080206@redhat.com> (Jason Merrill's message of "Wed, 20 Oct 2010 19:53:07 -0400") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2010-10/txt/msg02065.txt.bz2 Jason Merrill writes: > On 10/20/2010 05:37 PM, Dodji Seketeli wrote: >> + /* Only substitute into template non-type parms. */ >> + if (parameter != NULL_TREE >> + && TREE_CODE (parameter) == TREE_LIST >> + && (TREE_CODE (TREE_VALUE (parameter)) == TYPE_DECL >> + || TREE_CODE (TREE_VALUE (parameter)) == TEMPLATE_DECL)) >> + continue; >> + >> + if (!dependent_type_p (TREE_TYPE (TREE_VALUE (parameter)))) >> + continue; > > These optimizations seem unsafe: > > template class V> ... > template class U> ... > > Let's handle all parms, and check in fixup_template_parm* to see if a > parm has the right NUM_SIBLINGS before we try to adjust it; I would > expect that the parms of a template template parm will already have > NUM_SIBLINGS set properly, we just need to substitute in the outer > parms. Done. It happened that tsubst* does access checking so we emit access related errors twice; once during the type fixup and once later as we were doing before. fixup_template_parm now disables access checking using push_deferring_access_checks. We also catch more errors at this point. In template/crash55.C, we have this: template struct A {}; Now that the default argument goes through tsubst we emit this message: test.cc:1:34: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression I don't know if the error message is useful, but I believe it's correct. So I adjusted the test. >> + Consider the level of the parms of TT; T and U both have >> + level 2; TT has no template parm of level 1. So in this case >> + the first element of full_template_args is NULL_TREE. If we >> + leave it like this TMPL_ARG_DEPTH on args returns 1 instead >> + of 2. This will make tsubst wrongly consider that T and U >> + have level 1. Instead, let's create a dummy vector as the >> + first element of full_template_args so that TMPL_ARG_DEPTH >> + returns the correct depth for args. >> + */ > > The */ should go on the last line of text, not on a line by itself. > Fixed. I have tested the patch below on x86-64-unknown-linux-gnu -- Dodji commit 9c3747e5f7be2f49c47251495cade3471a9ef988 Author: Dodji Seketeli Date: Mon Sep 13 12:12:21 2010 +0200 Restore canonical type comparison for dependent typedefs gcc/cp/ChangeLog: PR c++/45606 * cp-tree.h (TEMPLATE_TYPE_PARM_SIBLING_PARMS): Remove. (struct template_parm_index_s): New field. (TEMPLATE_PARM_NUM_SIBLINGS): New accessor. (process_template_parm): Extend the API to accept the number of template parms in argument. (cp_set_underlying_type): Remove this. * class.c (build_self_reference): Require canonical type equality back on the self reference of class. * decl2.c (grokfield): Require canonical type equality back on typedef class fields. * name-lookup.c (pushdecl_maybe_friend): Require canonical type equality back on typedefs. * parser.c (cp_parser_template_parameter_list): Do not require canonical type equality on dependent types created during template parameters parsing. * pt.c (fixup_template_type_parm_type, fixup_template_parm_index) (fixup_template_parm, fixup_template_parms): New private functions. (current_template_args): Declare this. (process_template_parm): Pass the total number of template parms to canonical_type_parameter. (build_template_parm_index): Add a new argument to carry the total number of template parms. (reduce_template_parm_level, process_template_parm, make_auto): Adjust. (current_template_args): Fix this for template template parameters. (tsubst_template_parm): Split out of ... (tsubst_template_parms): ... this. (reduce_template_parm_level): Don't loose TEMPLATE_PARM_NUM_SIBLINGS when cloning a TEMPLATE_PARM_INDEX. (template_parm_to_arg): Extracted this function ... (current_template_args): ... from this one. (end_template_parm_list): Do not update template sibling parms here anymore. Use fixup_template_parms instead. (process_template_parm): Pass the number of template parms to canonical_type_parameter. (make_auto): Require structural equality on auto TEMPLATE_TYPE_PARM for now. (unify): Coerce template parameters using all the arguments deduced so far. (tsubst): Pass the number of sibling parms to canonical_type_parameter. * tree.c (cp_set_underlying_type): Remove. * typeck.c (get_template_parms_of_dependent_type) (incompatible_dependent_types_p): Remove. (structural_comptypes): Do not call incompatible_dependent_types_p anymore. (comp_template_parms_position): Re-organized. Take the length of template parms list in account. gcc/testsuite/ChangeLog: PR c++/45606 * gcc/testsuite/g++.dg/template/crash55.C: Adjust. * g++.dg/template/typedef36.C: New test. * gcc/testsuite/g++.dg/template/canon-type-9.C: Likewise. * g++.dg/template/canon-type-10.C: Likewise. * g++.dg/template/canon-type-11.C: Likewise. * g++.dg/template/canon-type-12.C: Likewise. * g++.dg/template/canon-type-13.C: Likewise. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f76c2be..d03b5b1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6690,7 +6690,7 @@ build_self_reference (void) DECL_CONTEXT (value) = current_class_type; DECL_ARTIFICIAL (value) = 1; SET_DECL_SELF_REFERENCE_P (value); - cp_set_underlying_type (value); + set_underlying_type (value); if (processing_template_decl) value = push_template_decl (value); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 626e452..1c009e5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -236,6 +236,7 @@ struct GTY(()) template_parm_index_s { int index; int level; int orig_level; + int num_siblings; tree decl; }; typedef struct template_parm_index_s template_parm_index; @@ -4306,6 +4307,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; ((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE)) #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index) #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level) +/* The Number of sibling parms this template parm has. */ +#define TEMPLATE_PARM_NUM_SIBLINGS(NODE) \ + (TEMPLATE_PARM_INDEX_CAST (NODE)->num_siblings) #define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE)) #define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level) #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl) @@ -4327,10 +4331,6 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; (TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (NODE))) #define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \ (TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE))) -/* The list of template parms that a given template parameter of type - TEMPLATE_TYPE_PARM belongs to.*/ -#define TEMPLATE_TYPE_PARM_SIBLING_PARMS(NODE) \ - (TREE_CHECK ((NODE), TEMPLATE_TYPE_PARM))->type.maxval /* These constants can used as bit flags in the process of tree formatting. @@ -5012,7 +5012,7 @@ extern void append_type_to_template_for_access_check (tree, tree, tree, extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); extern tree process_template_parm (tree, location_t, tree, - bool, bool); + bool, bool, unsigned); extern tree end_template_parm_list (tree); extern void end_template_decl (void); extern tree maybe_update_decl_type (tree, tree); @@ -5348,7 +5348,6 @@ extern bool type_has_nontrivial_copy_init (const_tree); extern bool class_tmpl_impl_spec_p (const_tree); extern int zero_init_p (const_tree); extern tree strip_typedefs (tree); -extern void cp_set_underlying_type (tree); extern tree copy_binfo (tree, tree, tree, tree *, int); extern int member_p (const_tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index f27e7d6..0c64661 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -879,7 +879,7 @@ grokfield (const cp_declarator *declarator, if (declspecs->specs[(int)ds_typedef] && TREE_TYPE (value) != error_mark_node && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value) - cp_set_underlying_type (value); + set_underlying_type (value); return value; } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 8b2e542..0a93da8 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -872,7 +872,7 @@ pushdecl_maybe_friend (tree x, bool is_friend) inlining. */ && (!TYPE_NAME (type) || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))) - cp_set_underlying_type (x); + set_underlying_type (x); if (type != error_mark_node && TYPE_NAME (type) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8c0129b..26eeca7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11026,6 +11026,13 @@ cp_parser_template_parameter_list (cp_parser* parser) tree parameter_list = NULL_TREE; begin_template_parm_list (); + + /* The loop below parses the template parms. We first need to know + the total number of template parms to be able to compute proper + canonical types of each dependent type. So after the loop, when + we know the total number of template parms, + end_template_parm_list computes the proper canonical types and + fixes up the dependent types accordingly. */ while (true) { tree parameter; @@ -11044,11 +11051,11 @@ cp_parser_template_parameter_list (cp_parser* parser) parm_loc, parameter, is_non_type, - is_parameter_pack); + is_parameter_pack, + 0); else { tree err_parm = build_tree_list (parameter, parameter); - TREE_VALUE (err_parm) = error_mark_node; parameter_list = chainon (parameter_list, err_parm); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 85a5ea5..263b939 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -137,7 +137,7 @@ static tree convert_template_argument (tree, tree, tree, static int for_each_template_parm (tree, tree_fn_t, void*, struct pointer_set_t*, bool); static tree expand_template_argument_pack (tree); -static tree build_template_parm_index (int, int, int, tree, tree); +static tree build_template_parm_index (int, int, int, int, tree, tree); static bool inline_needs_template_parms (tree); static void push_inline_template_parms_recursive (tree, int); static tree retrieve_local_specialization (tree); @@ -190,6 +190,12 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree, static hashval_t iterative_hash_template_arg (tree arg, hashval_t val); static tree listify (tree); static tree listify_autos (tree, tree); +static tree template_parm_to_arg (tree t); +static tree current_template_args (void); +static tree fixup_template_type_parm_type (tree, int); +static tree fixup_template_parm_index (tree, tree, int); +static void fixup_template_parms (void); +static tree tsubst_template_parm (tree, tree, tsubst_flags_t); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function @@ -3346,12 +3352,14 @@ check_template_shadow (tree decl) } /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL, - ORIG_LEVEL, DECL, and TYPE. */ + ORIG_LEVEL, DECL, and TYPE. NUM_SIBLINGS is the total number of + template parameters. */ static tree build_template_parm_index (int index, int level, int orig_level, + int num_siblings, tree decl, tree type) { @@ -3359,6 +3367,7 @@ build_template_parm_index (int index, TEMPLATE_PARM_IDX (t) = index; TEMPLATE_PARM_LEVEL (t) = level; TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level; + TEMPLATE_PARM_NUM_SIBLINGS (t) = num_siblings; TEMPLATE_PARM_DECL (t) = decl; TREE_TYPE (t) = type; TREE_CONSTANT (t) = TREE_CONSTANT (decl); @@ -3370,6 +3379,7 @@ build_template_parm_index (int index, /* Find the canonical type parameter for the given template type parameter. Returns the canonical type parameter, which may be TYPE if no such parameter existed. */ + static tree canonical_type_parameter (tree type) { @@ -3423,6 +3433,7 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args, t = build_template_parm_index (TEMPLATE_PARM_IDX (index), TEMPLATE_PARM_LEVEL (index) - levels, TEMPLATE_PARM_ORIG_LEVEL (index), + TEMPLATE_PARM_NUM_SIBLINGS (index), decl, type); TEMPLATE_PARM_DESCENDANTS (index) = t; TEMPLATE_PARM_PARAMETER_PACK (t) @@ -3438,15 +3449,20 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args, return TEMPLATE_PARM_DESCENDANTS (index); } -/* Process information from new template parameter PARM and append it to the - LIST being built. This new parameter is a non-type parameter iff - IS_NON_TYPE is true. This new parameter is a parameter - pack iff IS_PARAMETER_PACK is true. The location of PARM is in - PARM_LOC. */ +/* Process information from new template parameter PARM and append it + to the LIST being built. This new parameter is a non-type + parameter iff IS_NON_TYPE is true. This new parameter is a + parameter pack iff IS_PARAMETER_PACK is true. The location of PARM + is in PARM_LOC. NUM_TEMPLATE_PARMS is the size of the template + parameter list PARM belongs to. This is used used to create a + proper canonical type for the type of PARM that is to be created, + iff PARM is a type. If the size is not known, this parameter shall + be set to 0. */ tree -process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_type, - bool is_parameter_pack) +process_template_parm (tree list, location_t parm_loc, tree parm, + bool is_non_type, bool is_parameter_pack, + unsigned num_template_parms) { tree decl = 0; tree defval; @@ -3521,6 +3537,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_ty DECL_INITIAL (parm) = DECL_INITIAL (decl) = build_template_parm_index (idx, processing_template_decl, processing_template_decl, + num_template_parms, decl, TREE_TYPE (parm)); TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) @@ -3554,6 +3571,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_ty TEMPLATE_TYPE_PARM_INDEX (t) = build_template_parm_index (idx, processing_template_decl, processing_template_decl, + num_template_parms, decl, TREE_TYPE (parm)); TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack; TYPE_CANONICAL (t) = canonical_type_parameter (t); @@ -3586,16 +3604,323 @@ end_template_parm_list (tree parms) next = TREE_CHAIN (parm); TREE_VEC_ELT (saved_parmlist, nparms) = parm; TREE_CHAIN (parm) = NULL_TREE; - if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL) - TEMPLATE_TYPE_PARM_SIBLING_PARMS (TREE_TYPE (TREE_VALUE (parm))) = - current_template_parms; } + fixup_template_parms (); + --processing_template_parmlist; return saved_parmlist; } +/* Create a new type almost identical to TYPE but which has the + following differences: + + 1/ T has a new TEMPLATE_PARM_INDEX that carries the new number of + template sibling parameters of T. + + 2/ T has a new canonical type that matches the new number + of sibling parms. + + 3/ From now on, T is going to be what lookups referring to the + name of TYPE will return. No lookup should return TYPE anymore. + + NUM_PARMS is the new number of sibling parms TYPE belongs to. + + This is a subroutine of fixup_template_parms. */ + +static tree +fixup_template_type_parm_type (tree type, int num_parms) +{ + tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx; + tree t; + /* This is the decl which name is inserted into the symbol table for + the template parm type. So whenever we lookup the type name, this + is the DECL we get. */ + tree decl; + + /* Do not fix up the type twice. */ + if (orig_idx && TEMPLATE_PARM_NUM_SIBLINGS (orig_idx) != 0) + return type; + + t = copy_type (type); + decl = TYPE_NAME (t); + + TYPE_MAIN_VARIANT (t) = t; + TYPE_NEXT_VARIANT (t)= NULL_TREE; + TYPE_POINTER_TO (t) = 0; + TYPE_REFERENCE_TO (t) = 0; + + idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx), + TEMPLATE_PARM_LEVEL (orig_idx), + TEMPLATE_PARM_ORIG_LEVEL (orig_idx), + num_parms, + decl, t); + TEMPLATE_PARM_DESCENDANTS (idx) = TEMPLATE_PARM_DESCENDANTS (orig_idx); + TEMPLATE_PARM_PARAMETER_PACK (idx) = TEMPLATE_PARM_PARAMETER_PACK (orig_idx); + TEMPLATE_TYPE_PARM_INDEX (t) = idx; + + TYPE_STUB_DECL (t) = decl; + TEMPLATE_TYPE_DECL (t) = decl; + if (TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM) + TREE_TYPE (DECL_TEMPLATE_RESULT (decl)) = t; + + /* Update the type associated to the type name stored in the symbol + table. Now, whenever the type name is looked up, the resulting + type is properly fixed up. */ + TREE_TYPE (decl) = t; + + TYPE_CANONICAL (t) = canonical_type_parameter (t); + + return t; +} + +/* Create and return a new TEMPLATE_PARM_INDEX that is almost + identical to I, but that is fixed up as to: + + 1/ carry the number of sibling parms (NUM_PARMS) of the template + parm represented by I. + + 2/ replace all references to template parm types declared before I + (in the same template parm list as I) by references to template + parm types contained in ARGS. ARGS should contain the list of + template parms that have been fixed up so far, in a form suitable + to be passed to tsubst. + + This is a subroutine of fixup_template_parms. */ + +static tree +fixup_template_parm_index (tree i, tree args, int num_parms) +{ + tree index, decl, type; + + if (i == NULL_TREE + || TREE_CODE (i) != TEMPLATE_PARM_INDEX + /* Do not fix up the index twice. */ + || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0)) + return i; + + decl = TEMPLATE_PARM_DECL (i); + type = TREE_TYPE (decl); + + index = build_template_parm_index (TEMPLATE_PARM_IDX (i), + TEMPLATE_PARM_LEVEL (i), + TEMPLATE_PARM_ORIG_LEVEL (i), + num_parms, + decl, type); + + TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i); + TEMPLATE_PARM_PARAMETER_PACK (index) = TEMPLATE_PARM_PARAMETER_PACK (i); + + type = tsubst (type, args, tf_none, NULL_TREE); + + TREE_TYPE (decl) = type; + TREE_TYPE (index) = type; + + return index; +} + +/* + This is a subroutine of fixup_template_parms. + + It computes the canonical type of the type of the template + parameter PARM_DESC and update all references to that type so that + they use the newly computed canonical type. No access check is + performed during the fixup. PARM_DESC is a TREE_LIST which + TREE_VALUE is the template parameter and its TREE_PURPOSE is the + default argument of the template parm if any. IDX is the index of + the template parameter, starting at 0. NUM_PARMS is the number of + template parameters in the set PARM_DESC belongs to. ARGLIST is a + TREE_VEC containing the full set of template parameters in a form + suitable to be passed to substs functions as their ARGS + argument. This is what current_template_args returns for a given + template. The innermost vector of args in ARGLIST is the set of + template parms that have been fixed up so far. This function adds + the fixed up parameter into that vector. */ + +static void +fixup_template_parm (tree parm_desc, + int idx, + int num_parms, + tree arglist) +{ + tree parm = TREE_VALUE (parm_desc); + tree fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist); + + push_deferring_access_checks (dk_no_check); + + if (TREE_CODE (parm) == TYPE_DECL) + { + /* PARM is a template type parameter. Fix up its type, add + the fixed-up template parm to the vector of fixed-up + template parms so far, and substitute the fixed-up + template parms into the default argument of this + parameter. */ + tree t = + fixup_template_type_parm_type (TREE_TYPE (parm), num_parms); + TREE_TYPE (parm) = t; + + TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc); + } + else if (TREE_CODE (parm) == TEMPLATE_DECL) + { + /* PARM is a template template parameter. This is going to + be interesting. */ + tree tparms, targs, innermost_args; + int j; + + /* First, fix up the type of the parm. */ + + tree t = + fixup_template_type_parm_type (TREE_TYPE (parm), num_parms); + TREE_TYPE (parm) = t; + + TREE_VEC_ELT (fixedup_args, idx) = + template_parm_to_arg (parm_desc); + + /* Now we need to substitute the template parm types that + have been fixed up so far into the non-type template + parms of this template template parm. E.g, consider this: + + template class TT> class S; + + In this case we want to substitute T into the + template parameters of TT. + + Sot let's walk the template parms of PARM here, and + tsubst ARGLIST into into each of the template + parms. */ + + /* For this substitution we need to build the full set of + template parameters and use that as arguments for the + tsubsting function. */ + tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm)); + + /* This will contain the innermost parms of PARM into which + we have substituted so far. */ + innermost_args = make_tree_vec (TREE_VEC_LENGTH (tparms)); + targs = add_to_template_args (arglist, innermost_args); + for (j = 0; j < TREE_VEC_LENGTH (tparms); ++j) + { + tree parameter; + + parameter = TREE_VEC_ELT (tparms, j); + + /* INNERMOST_ARGS needs to have at least the same number + of elements as the index PARAMETER, ortherwise + tsubsting into PARAMETER will result in partially + instantiating it, reducing its tempate parm + level. Let's tactically fill INNERMOST_ARGS for that + purpose. */ + TREE_VEC_ELT (innermost_args, j) = + template_parm_to_arg (parameter); + + /* Only substitute into template non-type parms. */ + if (parameter != NULL_TREE + && TREE_CODE (parameter) == TREE_LIST + && (TREE_CODE (TREE_VALUE (parameter)) == TYPE_DECL + || TREE_CODE (TREE_VALUE (parameter)) == TEMPLATE_DECL)) + continue; + + if (!dependent_type_p (TREE_TYPE (TREE_VALUE (parameter)))) + continue; + + fixup_template_parm (parameter, j, + TREE_VEC_LENGTH (tparms), + targs); + } + } + else if (TREE_CODE (parm) == PARM_DECL) + { + /* PARM is a non-type template parameter. We need to: + + * Fix up its TEMPLATE_PARM_INDEX to make it carry the + proper number of sibling parameters. + + * Make lookups of the template parameter return a reference + to the fixed-up index. No lookup should return references + to the former index anymore. + + * Substitute the template parms that got fixed up so far + + * into the type of PARM. */ + + tree index = DECL_INITIAL (parm); + + /* PUSHED_DECL is the decl added to the symbol table with + the name of the parameter. E,g: + + template //#0 + auto my_function(T t) -> decltype(u); //#1 + + Here, when looking up u at //#1, we get the decl of u + resulting from the declaration in #0. This is what + PUSHED_DECL is. We need to replace the reference to the + old TEMPLATE_PARM_INDEX carried by PUSHED_DECL by the + fixed-up TEMPLATE_PARM_INDEX. */ + tree pushed_decl = TEMPLATE_PARM_DECL (index); + + /* Let's fix up the TEMPLATE_PARM_INDEX then. Note that we must + fixup the type of PUSHED_DECL as well and luckily + fixup_template_parm_index does it for us too. */ + tree fixed_up_index = + fixup_template_parm_index (index, arglist, num_parms); + + DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index; + + /* Add this fixed up PARM to the template parms we've fixed + up so far and use that to substitute the fixed-up + template parms into the type of PARM. */ + TREE_VEC_ELT (fixedup_args, idx) = + template_parm_to_arg (parm_desc); + TREE_TYPE (parm) = tsubst (TREE_TYPE (parm), arglist, + tf_warning_or_error, NULL_TREE); + } + + TREE_PURPOSE (parm_desc) = + tsubst_template_arg (TREE_PURPOSE (parm_desc), arglist, + tf_warning_or_error, parm); + + pop_deferring_access_checks (); +} + +/* Walk current the template parms and properly compute the canonical + types of the dependent types created during + cp_parser_template_parameter_list. */ + +static void +fixup_template_parms (void) +{ + tree arglist; + tree parameter_vec; + tree fixedup_args; + int i, num_parms; + + parameter_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms); + if (parameter_vec == NULL_TREE) + return; + + num_parms = TREE_VEC_LENGTH (parameter_vec); + + /* This vector contains the current innermost template parms that + have been fixed up so far. The form of FIXEDUP_ARGS is suitable + to be passed to tsubst* functions as their ARGS argument. */ + fixedup_args = make_tree_vec (num_parms); + + /* This vector contains the full set of template parms in a form + suitable to be passed to substs functions as their ARGS + argument. */ + arglist = current_template_args (); + arglist = add_outermost_template_args (arglist, fixedup_args); + + fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist); + + /* Let's do the proper fixup now. */ + for (i = 0; i < num_parms; ++i) + fixup_template_parm (TREE_VEC_ELT (parameter_vec, i), + i, num_parms, arglist); +} + /* end_template_decl is called after a template declaration is seen. */ void @@ -3613,6 +3938,65 @@ end_template_decl (void) current_template_parms = TREE_CHAIN (current_template_parms); } +/* Takes a TREE_LIST representing a template parameter and convert it + into an argument suitable to be passed to the type substitution + functions. */ + +static tree +template_parm_to_arg (tree t) +{ + + if (t == NULL_TREE + || TREE_CODE (t) != TREE_LIST + || error_operand_p (TREE_VALUE (t))) + return t; + + t = TREE_VALUE (t); + + if (TREE_CODE (t) == TYPE_DECL + || TREE_CODE (t) == TEMPLATE_DECL) + { + t = TREE_TYPE (t); + + if (TEMPLATE_TYPE_PARAMETER_PACK (t)) + { + /* Turn this argument into a TYPE_ARGUMENT_PACK + with a single element, which expands T. */ + tree vec = make_tree_vec (1); +#ifdef ENABLE_CHECKING + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT + (vec, TREE_VEC_LENGTH (vec)); +#endif + TREE_VEC_ELT (vec, 0) = make_pack_expansion (t); + + t = cxx_make_type (TYPE_ARGUMENT_PACK); + SET_ARGUMENT_PACK_ARGS (t, vec); + } + } + else + { + t = DECL_INITIAL (t); + + if (TEMPLATE_PARM_PARAMETER_PACK (t)) + { + /* Turn this argument into a NONTYPE_ARGUMENT_PACK + with a single element, which expands T. */ + tree vec = make_tree_vec (1); + tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t)); +#ifdef ENABLE_CHECKING + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT + (vec, TREE_VEC_LENGTH (vec)); +#endif + TREE_VEC_ELT (vec, 0) = make_pack_expansion (t); + + t = make_node (NONTYPE_ARGUMENT_PACK); + SET_ARGUMENT_PACK_ARGS (t, vec); + TREE_TYPE (t) = type; + } + } + return t; +} + /* Within the declaration of a template, return all levels of template parameters that apply. The template parameters are represented as a TREE_VEC, in the form documented in cp-tree.h for template @@ -3639,63 +4023,7 @@ current_template_args (void) TREE_TYPE (a) = NULL_TREE; for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) - { - tree t = TREE_VEC_ELT (a, i); - - /* T will be a list if we are called from within a - begin/end_template_parm_list pair, but a vector directly - if within a begin/end_member_template_processing pair. */ - if (TREE_CODE (t) == TREE_LIST) - { - t = TREE_VALUE (t); - - if (!error_operand_p (t)) - { - if (TREE_CODE (t) == TYPE_DECL - || TREE_CODE (t) == TEMPLATE_DECL) - { - t = TREE_TYPE (t); - - if (TEMPLATE_TYPE_PARAMETER_PACK (t)) - { - /* Turn this argument into a TYPE_ARGUMENT_PACK - with a single element, which expands T. */ - tree vec = make_tree_vec (1); -#ifdef ENABLE_CHECKING - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT - (vec, TREE_VEC_LENGTH (vec)); -#endif - TREE_VEC_ELT (vec, 0) = make_pack_expansion (t); - - t = cxx_make_type (TYPE_ARGUMENT_PACK); - SET_ARGUMENT_PACK_ARGS (t, vec); - } - } - else - { - t = DECL_INITIAL (t); - - if (TEMPLATE_PARM_PARAMETER_PACK (t)) - { - /* Turn this argument into a NONTYPE_ARGUMENT_PACK - with a single element, which expands T. */ - tree vec = make_tree_vec (1); - tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t)); -#ifdef ENABLE_CHECKING - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT - (vec, TREE_VEC_LENGTH (vec)); -#endif - TREE_VEC_ELT (vec, 0) = make_pack_expansion (t); - - t = make_node (NONTYPE_ARGUMENT_PACK); - SET_ARGUMENT_PACK_ARGS (t, vec); - TREE_TYPE (t) = type; - } - } - TREE_VEC_ELT (a, i) = t; - } - } - } + TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i)); #ifdef ENABLE_CHECKING SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a)); @@ -3707,6 +4035,21 @@ current_template_args (void) args = a; } + if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE) + /* This can happen for template parms of a template template + parameter, e.g: + + template class TT> struct S; + + Consider the level of the parms of TT; T and U both have + level 2; TT has no template parm of level 1. So in this case + the first element of full_template_args is NULL_TREE. If we + leave it like this TMPL_ARG_DEPTH on args returns 1 instead + of 2. This will make tsubst wrongly consider that T and U + have level 1. Instead, let's create a dummy vector as the + first element of full_template_args so that TMPL_ARG_DEPTH + returns the correct depth for args. */ + TREE_VEC_ELT (args, 0) = make_tree_vec (1); return args; } @@ -8744,8 +9087,6 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i) { tree tuple; - tree default_value; - tree parm_decl; if (parms == error_mark_node) continue; @@ -8755,18 +9096,8 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) if (tuple == error_mark_node) continue; - default_value = TREE_PURPOSE (tuple); - parm_decl = TREE_VALUE (tuple); - - parm_decl = tsubst (parm_decl, args, complain, NULL_TREE); - if (TREE_CODE (parm_decl) == PARM_DECL - && invalid_nontype_parm_type_p (TREE_TYPE (parm_decl), complain)) - parm_decl = error_mark_node; - default_value = tsubst_template_arg (default_value, args, - complain, NULL_TREE); - - tuple = build_tree_list (default_value, parm_decl); - TREE_VEC_ELT (new_vec, i) = tuple; + TREE_VEC_ELT (new_vec, i) = + tsubst_template_parm (tuple, args, complain); } *new_parms = @@ -8780,6 +9111,36 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) return r; } +/* Return the result of substituting ARGS into one template parameter + given by T. T Must be a TREE_LIST which TREE_VALUE is the template + parameter and which TREE_PURPOSE is the default argument of the + template parameter. */ + +static tree +tsubst_template_parm (tree t, tree args, tsubst_flags_t complain) +{ + tree default_value, parm_decl; + + if (args == NULL_TREE + || t == NULL_TREE + || t == error_mark_node) + return t; + + gcc_assert (TREE_CODE (t) == TREE_LIST); + + default_value = TREE_PURPOSE (t); + parm_decl = TREE_VALUE (t); + + parm_decl = tsubst (parm_decl, args, complain, NULL_TREE); + if (TREE_CODE (parm_decl) == PARM_DECL + && invalid_nontype_parm_type_p (TREE_TYPE (parm_decl), complain)) + parm_decl = error_mark_node; + default_value = tsubst_template_arg (default_value, args, + complain, NULL_TREE); + + return build_tree_list (default_value, parm_decl); +} + /* Substitute the ARGS into the indicated aggregate (or enumeration) type T. If T is not an aggregate or enumeration type, it is handled as if by tsubst. IN_DECL is as for tsubst. If @@ -14720,6 +15081,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) { tree parmvec = TYPE_TI_ARGS (parm); tree argvec = INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (arg)); + tree full_argvec = add_to_template_args (targs, argvec); tree parm_parms = DECL_INNERMOST_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (parm)); @@ -14754,7 +15116,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) the global operator+ will be used; if they are not, the Lvalue_proxy will be converted to float. */ if (coerce_template_parms (parm_parms, - argvec, + full_argvec, TYPE_TI_TEMPLATE (parm), tf_none, /*require_all_args=*/true, @@ -18428,7 +18790,7 @@ make_auto (void) TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index (0, processing_template_decl + 1, processing_template_decl + 1, - TYPE_NAME (au), NULL_TREE); + 0, TYPE_NAME (au), NULL_TREE); TYPE_CANONICAL (au) = canonical_type_parameter (au); DECL_ARTIFICIAL (TYPE_NAME (au)) = 1; SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au)); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index b8f76b0..7e33693 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1062,22 +1062,6 @@ strip_typedefs (tree t) return cp_build_qualified_type (result, cp_type_quals (t)); } -/* Setup a TYPE_DECL node as a typedef representation. - See comments of set_underlying_type in c-common.c. */ - -void -cp_set_underlying_type (tree t) -{ - set_underlying_type (t); - /* If T is a template type parm, make it require structural equality. - This is useful when comparing two template type parms, - because it forces the comparison of the template parameters of their - decls. */ - if (TREE_CODE (TREE_TYPE (t)) == TEMPLATE_TYPE_PARM) - SET_TYPE_STRUCTURAL_EQUALITY (TREE_TYPE (t)); -} - - /* Makes a copy of BINFO and TYPE, which is to be inherited into a graph dominated by T. If BINFO is NULL, TYPE is a dependent base, and we do a shallow copy. If BINFO is non-NULL, we do a deep copy. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 160198b..76d6f12 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1143,120 +1143,30 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration) static bool comp_template_parms_position (tree t1, tree t2) { + tree index1, index2; gcc_assert (t1 && t2 && TREE_CODE (t1) == TREE_CODE (t2) && (TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM || TREE_CODE (t1) == TEMPLATE_TYPE_PARM)); - if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2) - || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2) - || (TEMPLATE_TYPE_PARAMETER_PACK (t1) - != TEMPLATE_TYPE_PARAMETER_PACK (t2))) - return false; - - return true; -} - -/* Subroutine of incompatible_dependent_types_p. - Return the template parameter of the dependent type T. - If T is a typedef, return the template parameters of - the _decl_ of the typedef. T must be a dependent type. */ - -static tree -get_template_parms_of_dependent_type (tree t) -{ - tree tinfo = NULL_TREE, tparms = NULL_TREE; - - /* First, try the obvious case of getting the - template info from T itself. */ - if ((tinfo = get_template_info (t))) - ; - else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) - return TEMPLATE_TYPE_PARM_SIBLING_PARMS (t); - else if (typedef_variant_p (t) - && !NAMESPACE_SCOPE_P (TYPE_NAME (t))) - tinfo = get_template_info (DECL_CONTEXT (TYPE_NAME (t))); - /* If T is a TYPENAME_TYPE which context is a template type - parameter, get the template parameters from that context. */ - else if (TYPE_CONTEXT (t) - && TREE_CODE (TYPE_CONTEXT (t)) == TEMPLATE_TYPE_PARM) - return TEMPLATE_TYPE_PARM_SIBLING_PARMS (TYPE_CONTEXT (t)); - else if (TYPE_CONTEXT (t) - && !NAMESPACE_SCOPE_P (t)) - tinfo = get_template_info (TYPE_CONTEXT (t)); - - if (tinfo) - tparms = DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)); - - return tparms; -} - -/* Subroutine of structural_comptypes. - Compare the dependent types T1 and T2. - Return TRUE if we are sure they can't be equal, FALSE otherwise. - The whole point of this function is to support cases where either T1 or - T2 is a typedef. In those cases, we need to compare the template parameters - of the _decl_ of the typedef. If those don't match then we know T1 - and T2 cannot be equal. */ - -static bool -incompatible_dependent_types_p (tree t1, tree t2) -{ - tree tparms1 = NULL_TREE, tparms2 = NULL_TREE; - bool t1_typedef_variant_p, t2_typedef_variant_p; - - if (!uses_template_parms (t1) || !uses_template_parms (t2)) - return false; - - if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM) - { - /* If T1 and T2 don't have the same relative position in their - template parameters set, they can't be equal. */ - if (!comp_template_parms_position (t1, t2)) - return true; - } - - t1_typedef_variant_p = typedef_variant_p (t1); - t2_typedef_variant_p = typedef_variant_p (t2); + index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1)); + index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2)); - /* Either T1 or T2 must be a typedef. */ - if (!t1_typedef_variant_p && !t2_typedef_variant_p) + /* If T1 and T2 belong to template parm lists of different size, + let's assume they are different. */ + if (TEMPLATE_PARM_NUM_SIBLINGS (index1) + != TEMPLATE_PARM_NUM_SIBLINGS (index2)) return false; - if (!t1_typedef_variant_p || !t2_typedef_variant_p) - /* Either T1 or T2 is not a typedef so we cannot compare the - template parms of the typedefs of T1 and T2. - At this point, if the main variant type of T1 and T2 are equal - it means the two types can't be incompatible, from the perspective - of this function. */ - if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) - return false; - - /* So if we reach this point, it means either T1 or T2 is a typedef variant. - Let's compare their template parameters. */ - - tparms1 = get_template_parms_of_dependent_type (t1); - tparms2 = get_template_parms_of_dependent_type (t2); - - /* If T2 is a template type parm and if we could not get the template - parms it belongs to, that means we have not finished parsing the - full set of template parameters of the template declaration it - belongs to yet. If we could get the template parms T1 belongs to, - that mostly means T1 and T2 belongs to templates that are - different and incompatible. */ - if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM - && (tparms1 == NULL_TREE || tparms2 == NULL_TREE) - && tparms1 != tparms2) - return true; - - if (tparms1 == NULL_TREE - || tparms2 == NULL_TREE - || tparms1 == tparms2) + /* Then compare their relative position. */ + if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2) + || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2) + || (TEMPLATE_PARM_PARAMETER_PACK (index1) + != TEMPLATE_PARM_PARAMETER_PACK (index2))) return false; - /* And now compare the mighty template parms! */ - return !comp_template_parms (tparms1, tparms2); + return true; } /* Subroutine in comptypes. */ @@ -1301,12 +1211,6 @@ structural_comptypes (tree t1, tree t2, int strict) if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2)) return false; - /* If T1 and T2 are dependent typedefs then check upfront that - the template parameters of their typedef DECLs match before - going down checking their subtypes. */ - if (incompatible_dependent_types_p (t1, t2)) - return false; - /* Allow for two different type nodes which have essentially the same definition. Note that we already checked for equality of the type qualifiers (just above). */ @@ -1407,8 +1311,10 @@ structural_comptypes (tree t1, tree t2, int strict) break; case TEMPLATE_TYPE_PARM: - /* If incompatible_dependent_types_p called earlier didn't decide - T1 and T2 were different, they might be equal. */ + /* If T1 and T2 don't have the same relative position in their + template parameters set, they can't be equal. */ + if (!comp_template_parms_position (t1, t2)) + return false; break; case TYPENAME_TYPE: diff --git a/gcc/testsuite/g++.dg/template/canon-type-10.C b/gcc/testsuite/g++.dg/template/canon-type-10.C new file mode 100644 index 0000000..0c38946 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/canon-type-10.C @@ -0,0 +1,23 @@ +// Contributed by Dodji Seketeli +// { dg-do "compile" } + +template +struct C +{ +}; + +template class TT_TT> class TT, + class U = TT > +struct S +{ + void foo(TT); +}; + +template class TT_TT> class TT, + class U> +void +S::foo(TT) +{ +} diff --git a/gcc/testsuite/g++.dg/template/canon-type-11.C b/gcc/testsuite/g++.dg/template/canon-type-11.C new file mode 100644 index 0000000..698fe31 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/canon-type-11.C @@ -0,0 +1,39 @@ +// Contributed by Dodji Seketeli +// { dg-do "compile" } + +template +struct C +{ + void bar(); +}; + +template +void +C::bar() +{ +} + + +template class TT0 = C, + template class TT1 = TT0> +struct S +{ + C s; + + void foo(TT1); + + void bar() + { + foo(s); + } +}; + +template class TT0, + template class TT1> +void +S::foo(TT1) +{ + C c; +} diff --git a/gcc/testsuite/g++.dg/template/canon-type-12.C b/gcc/testsuite/g++.dg/template/canon-type-12.C new file mode 100644 index 0000000..694cc5e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/canon-type-12.C @@ -0,0 +1,21 @@ +// { dg-options "-std=c++0x" } + +template +struct S +{ + void + foo(decltype(t) = t); +}; + +template +void +S::foo(T) +{ +} + +void +bar() +{ + S s; + s.foo(); +} diff --git a/gcc/testsuite/g++.dg/template/canon-type-13.C b/gcc/testsuite/g++.dg/template/canon-type-13.C new file mode 100644 index 0000000..ca39cea --- /dev/null +++ b/gcc/testsuite/g++.dg/template/canon-type-13.C @@ -0,0 +1,27 @@ +// Contributed by Dodji Seketeli +// { dg-do "compile" } + +template +struct S0 +{ +}; + +template +struct S1 +{ +}; + +template class A, template class B = A> +struct C +{ + B m; +}; + +void +foo() +{ + C s; + S0 s0; + + s.m = s0; +} diff --git a/gcc/testsuite/g++.dg/template/canon-type-9.C b/gcc/testsuite/g++.dg/template/canon-type-9.C new file mode 100644 index 0000000..de6170e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/canon-type-9.C @@ -0,0 +1,18 @@ +// Contributed by Dodji Seketeli +// { dg-options "-std=c++0x" } +// { dg-do "compile" } + +struct F { F(int) {}}; + +template +struct S +{ + decltype(u) foo(T); +}; + +template +T* S::foo(T) +{ + T t; + return t; +} diff --git a/gcc/testsuite/g++.dg/template/crash55.C b/gcc/testsuite/g++.dg/template/crash55.C index 7cf9f1e..c2a53e4 100644 --- a/gcc/testsuite/g++.dg/template/crash55.C +++ b/gcc/testsuite/g++.dg/template/crash55.C @@ -1,6 +1,6 @@ //PR c++/27668 -template // { dg-error "nested-name-specifier|two or more|valid type" } +template // { dg-error "nested-name-specifier|two or more|valid type|constant-expression" } struct A {}; template void foo(A); // { dg-error "mismatch|constant|template argument" } diff --git a/gcc/testsuite/g++.dg/template/typedef36.C b/gcc/testsuite/g++.dg/template/typedef36.C new file mode 100644 index 0000000..318deef --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef36.C @@ -0,0 +1,23 @@ +// Origin: PR c++/45606 +// { dg-do compile } + +template +struct S0 +{ + typedef int const_iterator; +}; + +template +struct Test +{ + typedef S0 SAlias; + typedef typename SAlias::const_iterator const_iterator; + const_iterator begin (); +}; + +template +typename S0::const_iterator +Test::begin() +{ + return 0; +}