From: dodji Date: Tue, 2 Nov 2010 12:44:19 +0000 (+0000) Subject: Restore canonical type comparison for dependent type(def)s X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=0d432ee0d0d07e9c17b69e06afc1be9d65f57546 Restore canonical type comparison for dependent type(def)s This patch restores canonical type comparison for dependent types and then dependent typedefs. After this patch, two template type parameters T are equal if they have the same index, level, *and* number of sibling parameters. The novelty is to take in account the number of sibling parameters. To do this we first build the template parameters w/o taking in account their number of siblings. When we know the number of template parameters we fix up each template parameter with the number of slibling parameters and we build the appropriate canonical types accordingly. The patch fixes the fallouts deemed necessary. This fixes PR c++/45606 but actually fixes all the previous bugs related to dependent typedef comparison we had since we started to properly representing 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 from current_template_args. Make it represent invalid template parms with an error_mark_node instead of a LIST_TREE containing an error_mark_node. (current_template_args): Use template_parm_to_arg. (dependent_template_arg_p): Consider an invalid template argument as dependent. (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 * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166179 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index df32c8a2702..1ab6854ea8a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,62 @@ +2010-11-02 Dodji Seketeli + + 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 from + current_template_args. Make it represent invalid template parms + with an error_mark_node instead of a LIST_TREE containing an + error_mark_node. + (current_template_args): Use template_parm_to_arg. + (dependent_template_arg_p): Consider an invalid template argument + as dependent. + (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. + 2010-11-01 Jason Merrill * semantics.c (call_stack, call_stack_tick, cx_error_context): New. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 217450c82c7..7aa697450d1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6768,7 +6768,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 f57efb91acf..b46959b7f98 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; @@ -4310,6 +4311,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) @@ -4331,10 +4335,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. @@ -5022,7 +5022,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); @@ -5366,7 +5366,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 0003601823c..a805c6b52d7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -864,7 +864,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 8b2e542e8a4..0a93da88083 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 90277603eeb..864ec9b2806 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11045,6 +11045,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; @@ -11063,11 +11070,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 d3c1c1ce8a3..e4975c6a112 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); @@ -189,6 +189,12 @@ static void append_type_to_template_for_access_check_1 (tree, tree, tree, location_t); 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 @@ -3353,12 +3359,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) { @@ -3366,6 +3374,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); @@ -3377,6 +3386,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) { @@ -3430,6 +3440,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) @@ -3445,15 +3456,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; @@ -3528,6 +3544,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)) @@ -3561,6 +3578,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); @@ -3593,16 +3611,313 @@ 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. + + So 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); + + 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_none, NULL_TREE); + } + + TREE_PURPOSE (parm_desc) = + tsubst_template_arg (TREE_PURPOSE (parm_desc), + arglist, tf_none, 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 @@ -3620,6 +3935,68 @@ 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. Note that If the TREE_LIST contains an error_mark + node, the returned argument is error_mark_node. */ + +static tree +template_parm_to_arg (tree t) +{ + + if (t == NULL_TREE + || TREE_CODE (t) != TREE_LIST) + return t; + + if (error_operand_p (TREE_VALUE (t))) + return error_mark_node; + + 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 @@ -3646,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)); @@ -3714,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; } @@ -8721,8 +9057,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; @@ -8732,18 +9066,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 = @@ -8757,6 +9081,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 @@ -14668,6 +15022,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)); @@ -14702,7 +15057,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, @@ -18007,6 +18362,13 @@ dependent_template_arg_p (tree arg) if (!processing_template_decl) return false; + /* Assume a template argument that was wrongly written by the user + is dependent. This is consistent with what + any_dependent_template_arguments_p [that calls this function] + does. */ + if (arg == error_mark_node) + return true; + if (TREE_CODE (arg) == TEMPLATE_DECL || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) return dependent_template_p (arg); @@ -18434,7 +18796,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 e55b5bc6f2a..d1d306e3a2a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1096,22 +1096,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 0da32786e05..5f8d32162f0 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/ChangeLog b/gcc/testsuite/ChangeLog index 9d56097e40e..b784b1cad8d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2010-11-02 Dodji Seketeli + + PR c++/45606 + * 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. + 2010-11-02 Iain Sandoe * g++.dg/debug/dwarf2/pubnames-1.C: Amend to check for only one instance 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 00000000000..0c38946ec0a --- /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 00000000000..698fe318827 --- /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 00000000000..694cc5e1379 --- /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 00000000000..ca39cea9124 --- /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 00000000000..de6170e9852 --- /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/typedef36.C b/gcc/testsuite/g++.dg/template/typedef36.C new file mode 100644 index 00000000000..318deef92df --- /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; +}