From patchwork Sat Sep 25 15:19:17 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 65746 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 75D8DB70F5 for ; Sun, 26 Sep 2010 01:19:41 +1000 (EST) Received: (qmail 5561 invoked by alias); 25 Sep 2010 15:19:37 -0000 Received: (qmail 5471 invoked by uid 22791); 25 Sep 2010 15:19:31 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,TW_SB X-Spam-Check-By: sourceware.org Received: from seketeli.net (HELO ms.seketeli.net) (91.121.166.71) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 25 Sep 2010 15:19:21 +0000 Received: from adjoa.torimasen.com (torimasen.com [82.237.12.13]) by ms.seketeli.net (Postfix) with ESMTP id 4D8791608038; Sat, 25 Sep 2010 17:17:10 +0200 (CEST) Received: from adjoa.seketeli.org (localhost.localdomain [127.0.0.1]) by adjoa.torimasen.com (Postfix) with ESMTP id A07618E6002; Sat, 25 Sep 2010 17:19:17 +0200 (CEST) From: Dodji Seketeli To: Jason Merrill Cc: "H.J. Lu" , Paolo Carlini , GCC Patches Subject: Re: Require canonical type comparison for typedefs again. References: <4C630F87.9060303@redhat.com> <4C640257.4080804@redhat.com> <4C9673B7.5010505@oracle.com> <4C97C9E5.2090907@redhat.com> X-URL: http://www.seketeli.net/~dodji Date: Sat, 25 Sep 2010 17:19:17 +0200 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hello, I have reworked the patch to address your points. Please see my comments below. Jason Merrill writes: > On 09/20/2010 12:29 PM, Dodji Seketeli wrote: >> #define TEMPLATE_TYPE_PARM_SIBLING_PARMS(NODE) \ >> - (TREE_CHECK ((NODE), TEMPLATE_TYPE_PARM))->type.maxval >> + (TREE_CHECK3 ((NODE), TEMPLATE_TYPE_PARM, \ >> + TEMPLATE_TEMPLATE_PARM, \ >> + BOUND_TEMPLATE_TEMPLATE_PARM))->type.maxval > > With your patch we aren't actually using this list anymore, only its > length, so we might as well just store the length directly rather than > the list. That way, this: > >> + /* If T1 belongs to a not-yet fully parsed template parameters >> + list, let's assume it's different from T2 which belongs to an >> + already fully parsed template template parameters list. */ >> + if ((TEMPLATE_TYPE_PARM_SIBLING_PARMS >> + (TYPE_MAIN_VARIANT (t1)) != NULL_TREE) >> + != (TEMPLATE_TYPE_PARM_SIBLING_PARMS >> + (TYPE_MAIN_VARIANT (t1)) != NULL_TREE)) >> + return false; >> + >> + /* If T1 and T2 belong to template parm lists of different >> + size, then can't be equal. */ >> + if ((TEMPLATE_TYPE_PARM_SIBLING_PARMS >> + (TYPE_MAIN_VARIANT (t1)) != NULL_TREE) >> + && (TEMPLATE_TYPE_PARM_SIBLING_PARMS >> + (TYPE_MAIN_VARIANT (t2)) != NULL_TREE) >> + && (TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS >> + (TEMPLATE_TYPE_PARM_SIBLING_PARMS >> + (TYPE_MAIN_VARIANT (t1)))) >> + != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS >> + (TEMPLATE_TYPE_PARM_SIBLING_PARMS >> + (TYPE_MAIN_VARIANT (t2)))))) >> + return false; > > Can become a single simple comparison. Which should go into > comp_template_parms_position. > Nice. I have done that. >> +/* Contains canonical template parameter types. The vector is indexed >> + by the TEMPLATE_TYPE_IDX of the template parameter. Each element is >> + a TREE_LIST, whose TREE_PURPOSE is a INT_CST tree representing a >> + total size of the template parameter list a given template >> + parameter would belong too, and whose TREE_VALUEs contain the >> + canonical template parameters of various types and levels, >> + belonging to a set of template parameters which size is >> + TREE_PURPOSE. */ >> static GTY(()) VEC(tree,gc) *canonical_template_parms; > > Since we're adding more elements to this table, maybe we should > convert it to a hash table. But that can be a follow-on patch. > Sure. I'll post a separate patch for it once we are done with this one. >> + if (total_num_parms == 0) >> + return NULL_TREE; > > Since you're already treating parms from a list of unknown length as > distinct from parms from a list of known length, we can give them a > canonical type, too. > Doing that doesn't seem to work. The problem is not with the comparison of type template parms but rather with the comparison of dependent types created during the template parms parsing. If type template parms don't require structural comparison then a type A (created during template parms parsing) dependent on those parms will have a canonical type. The fixup then creates a type A' that is structurally equivalent to A, but has a different canonical type. Later, possible calls to lookup_template_class could then compare A and A' and the sanity constraints activated by ENABLE_CHECKING in comptypes would be violated because two structurally equivalent types have different canonical types. We don't have the issue in comptypes if A doesn't have a canonical type to begin with. >> + if (TREE_CODE (parm) == TYPE_DECL >> + || TREE_CODE (parm) == TEMPLATE_DECL) >> + { >> + /* Compute the canonical type of type template >> + parameters and their variants. */ > > Hmm, don't we need to handle substituting type parameters into > template parameters? > > template class U> struct A { }; > > It should work to do a single loop over the template args, doing any > substitution and then replacing them with their canonical variants as > appropriate. Since a particular parameter can only refer to previous > ones, we can't run into ordering issues. > Good catch. I have done this but it made me scratch head for a little while because tsubsting into the parms of a template template parm wasn't as straight forward as I thought it would be. The issue where the followings. * Template parm level reduction. When at least one of the parms is itself a template [like in testsuite/g++.old-deja/g++.pt/nttp1.C] then at some point we end up in tsubst (at least) with an argument set that has a depth that is less than the depth of the parm of the template template parm we are susbtituting into. My understanding is that the tsubsting code then thinks that we are doing the substitution for the purpose of instantiation and then reduces the level of the resulting parms. In this current case though, we are not doing the substitution for the purpose of instantiation; we want the levels of all the resulting tsubsted parms to remain unchanged; we want an "in place substitution" so to speak. So I introduced a new tf_no_tpl_reduce (for "no template parm level reduce") flag in enum tsubst_flags and changed tsubst and tsubst_template_parms to avoid doing level reduction when passed this flag.] Incidentally I noticed that the tf_no_class_instantiation is not used by any client code anymore. Would you accept a patchlet to remove it? * I had to use use_template_parms in make_typename_type I know I have to be careful each time I use use_template_parms instead of dependent_type_p so I'll give some context. Consider this example distilled from testsuite/g++.dg/template/ttp25.C: ~=~ template struct metafun { typedef T type; }; template::type> class C> //#0 void f4(T, C<5>); template struct X {}; void g() { f4(5, X<5>()); // OK. } ~=~ Consider when we build the set of overload candidate functions for f4(5, X<5>()). add_template_candidate_real at some point tries to deduce the template argument to C. During unification of C<5> with X<5> the argument 5 of X is converted into the type of the parameter of C, i.e 5 is converted into typename metafun::type. convert_template_argument then tries to substitute into typename metafun::type. This should just create another equivalent typename becase metafun is dependent and thus non complete. But when tsubst calls make_typename_type, the later fails to detect that metafun is dependent [because processing_template_decl is 0] and goes crazy. As tsubst uses use_template_parms to detect that metafun is dependent before calling make_typename_type, I thought I'd use the same in the later. Interestingly, the reason why this wasn't happening before is, in #0, when lookup_class_template is called to build the type of metafun, that template-id is considered as naming template struct metafun; so its canonical type is set to the TREE_TYPE of the TEMPLATE_DECL of metafun. That type is complete. So later when make_typename_type is called during the overload resolution of f4(5, X<5>()), the "if (!dependent_scope_p (context))" succeeds and the call to t = lookup_field (context, name, 2, /*want_type=*/true); returns the field "type". Tested for the c++ languages against trunk on x86_64-unknown-linux-gnu. I am going launch a test for the other languages right away. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index c594d6a..1537786 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6673,7 +6673,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 c78beb7..cf936d2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3954,6 +3954,8 @@ enum tsubst_flags { when issuing other errors. */ /* Do not instantiate classes (used by count_non_default_template_args). */ tf_no_class_instantiations = 1 << 8, + tf_no_tpl_reduce = 1 << 9, /* Do not reduce the level of + template parameters. */ /* Convenient substitution flags combinations. */ tf_warning_or_error = tf_warning | tf_error }; @@ -4321,10 +4323,13 @@ 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 + +/* The length of the template parms list this template parm belongs + to. This is a an integer wrapped into a tree node. */ +#define TEMPLATE_NUM_SIBLING_PARMS(NODE) \ + (TREE_CHECK3 ((NODE), TEMPLATE_TYPE_PARM, \ + TEMPLATE_TEMPLATE_PARM, \ + BOUND_TEMPLATE_TEMPLATE_PARM))->type.maxval /* These constants can used as bit flags in the process of tree formatting. @@ -5005,7 +5010,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); @@ -5341,7 +5346,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/decl.c b/gcc/cp/decl.c index 3d1420a..e4d39a8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3099,7 +3099,7 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, else t = NULL_TREE; - if ((!t || TREE_CODE (t) == TREE_LIST) && dependent_type_p (context)) + if ((!t || TREE_CODE (t) == TREE_LIST) && uses_template_parms (context)) return build_typename_type (context, name, fullname, tag_type); want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 63197705..1c6bbbe 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 41feb57..a044659 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 9385344..b8c35b3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10997,6 +10997,15 @@ cp_parser_template_parameter_list (cp_parser* parser) tree parameter_list = NULL_TREE; begin_template_parm_list (); + + /* The loop below parses the template parms. Note that dependent + types created during this parsing require structural comparison + rather than canonical type comparison. This is because we first + need to know the total number of template parms to be able to + compute 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; @@ -11015,11 +11024,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 5a90bdc..a4b13b1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -93,10 +93,14 @@ static GTY ((param_is (spec_entry))) static GTY ((param_is (spec_entry))) htab_t type_specializations; -/* Contains canonical template parameter types. The vector is indexed by - the TEMPLATE_TYPE_IDX of the template parameter. Each element is a - TREE_LIST, whose TREE_VALUEs contain the canonical template - parameters of various types and levels. */ +/* Contains canonical template parameter types. The vector is indexed + by the TEMPLATE_TYPE_IDX of the template parameter. Each element is + a TREE_LIST, whose TREE_PURPOSE is a INT_CST tree representing a + total size of the template parameter list a given template + parameter would belong too, and whose TREE_VALUEs contain the + canonical template parameters of various types and levels, + belonging to a set of template parameters which size is + TREE_PURPOSE. */ static GTY(()) VEC(tree,gc) *canonical_template_parms; #define UNIFY_ALLOW_NONE 0 @@ -190,6 +194,9 @@ 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 current_template_args (void); +static void fixup_template_parms_canonical_types (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 @@ -3369,12 +3376,25 @@ 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. */ + if no such parameter existed. TOTAL_NUM_PARMS is the number of + template parameters carried by the considered template. + + If TYPE is the template parameter at position P in a + template, this function won't return the same canonical type as for + a another TYPE that would be a template parameter at position Q, + with Q != P. + + If TOTAL_NUM_PARMS is 0, the function returns NULL_TREE. */ + static tree -canonical_type_parameter (tree type) +canonical_type_parameter (tree type, unsigned total_num_parms) { tree list; int idx = TEMPLATE_TYPE_IDX (type); + + if (total_num_parms == 0) + return NULL_TREE; + if (!canonical_template_parms) canonical_template_parms = VEC_alloc (tree, gc, idx+1); @@ -3382,15 +3402,20 @@ canonical_type_parameter (tree type) VEC_safe_push (tree, gc, canonical_template_parms, NULL_TREE); list = VEC_index (tree, canonical_template_parms, idx); - while (list && !comptypes (type, TREE_VALUE (list), COMPARE_STRUCTURAL)) - list = TREE_CHAIN (list); + while (list) + { + if (TREE_INT_CST_LOW (TREE_PURPOSE (list)) == total_num_parms + && comptypes (type, TREE_VALUE (list), COMPARE_STRUCTURAL)) + break; + list = TREE_CHAIN (list); + } if (list) return TREE_VALUE (list); else { VEC_replace(tree, canonical_template_parms, idx, - tree_cons (NULL_TREE, type, + tree_cons (size_int (total_num_parms), type, VEC_index (tree, canonical_template_parms, idx))); return type; } @@ -3438,15 +3463,21 @@ 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 can + be set to 0. Setting it to zero would create a template type + parameter with no canonical type. */ 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; @@ -3556,8 +3587,9 @@ process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_ty processing_template_decl, decl, TREE_TYPE (parm)); TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack; - TYPE_CANONICAL (t) = canonical_type_parameter (t); - } + TYPE_CANONICAL (t) = + canonical_type_parameter (t, num_template_parms); + } DECL_ARTIFICIAL (decl) = 1; SET_DECL_TEMPLATE_PARM_P (decl); pushdecl (decl); @@ -3573,9 +3605,9 @@ process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_ty tree end_template_parm_list (tree parms) { - int nparms; + int nparms, length = list_length (parms); tree parm, next; - tree saved_parmlist = make_tree_vec (list_length (parms)); + tree saved_parmlist = make_tree_vec (length); current_template_parms = tree_cons (size_int (processing_template_decl), @@ -3586,16 +3618,141 @@ 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; + if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL + || TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL) + TEMPLATE_NUM_SIBLING_PARMS (TREE_TYPE (TREE_VALUE (parm))) = + size_int (length); } + fixup_template_parms_canonical_types (); + --processing_template_parmlist; return saved_parmlist; } +/* 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_canonical_types (void) +{ + tree parm; + tree full_template_args; + tree parameter_vec; + 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); + + /* In this first loop, let's update the canonical type of each + type template parameter. */ + for (i = 0; i < num_parms; ++i) + { + tree main_type, variant; + + parm = TREE_VALUE (TREE_VEC_ELT (parameter_vec, i)); + if (TREE_CODE (parm) == TYPE_DECL + || TREE_CODE (parm) == TEMPLATE_DECL) + { + if (TREE_CODE (parm) == TEMPLATE_DECL) + { + tree arglist = current_template_args (); + tree tparms; + int j; + + /* So PARM is a template tempate parameter, e.g, like TT + in: + + 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. */ + tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm)); + for (j = 0; j < TREE_VEC_LENGTH (tparms); ++j) + { + tree substed_parm; + ++cp_unevaluated_operand; + /* Note the use of tf_no_tpl_reduce as the last + argument to tsubst_template_parm here. Suppose + the current template parameter of PARM is itself + a template. In that case, we do not want + tsubst_template_parm to reduce the level of the + parameters of that later template , as tsubst or + tsubst_template_parms would normally do [because + we are not tsubsting here for the purpose of + instantiating a type, rather, we just want to + substitute template parameters "in + place"]. Therefore, we use tf_no_tpl_reduce to + really avoid that template parm level + reduction. */ + substed_parm = tsubst_template_parm (TREE_VEC_ELT (tparms, j), + arglist, + tf_no_tpl_reduce); + --cp_unevaluated_operand; + TREE_VEC_ELT (tparms, j) = substed_parm; + } + } + + /* Compute the canonical type of type template + parameters and their variants. */ + main_type = TYPE_MAIN_VARIANT (TREE_TYPE (parm)); + TYPE_CANONICAL (main_type) = + canonical_type_parameter (main_type, num_parms); + for (variant = TYPE_NEXT_VARIANT (main_type); + variant; + variant = TYPE_NEXT_VARIANT (variant)) + TYPE_CANONICAL (variant) = + canonical_type_parameter (variant, num_parms); + } + } + + /* And now let's substitute the template type parameters into + dependent non-type template arguments and default template + arguments. */ + full_template_args = current_template_args (); + for (i = 0; i < num_parms; ++i) + { + tree cur = TREE_VEC_ELT (parameter_vec, i); + + if ((TREE_CODE (parm) == TYPE_DECL + || TREE_CODE (parm) == TEMPLATE_DECL) + && TREE_PURPOSE (cur)) + { + tree default_arg = TREE_PURPOSE (cur); + + if (TYPE_P (default_arg) + && !dependent_type_p (default_arg)) + continue; + + ++cp_unevaluated_operand; + TREE_PURPOSE (cur) = + tsubst_expr (default_arg, full_template_args, + tf_none, default_arg, false); + --cp_unevaluated_operand; + } + + if (TREE_CODE (TREE_VALUE (cur)) == PARM_DECL) + { + tree non_type_parm = TREE_VALUE (cur); + ++cp_unevaluated_operand; + TREE_VALUE (cur) = + tsubst_decl (non_type_parm, + full_template_args, + tf_none); + --cp_unevaluated_operand; + } + } +} + /* end_template_decl is called after a template declaration is seen. */ void @@ -3706,7 +3863,23 @@ current_template_args (void) else 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; } @@ -6681,16 +6854,22 @@ lookup_template_class (tree d1, if (context == current_function_decl) pushtag (DECL_NAME (gen_tmpl), t, /*tag_scope=*/ts_current); - if (comp_template_args (CLASSTYPE_TI_ARGS (template_type), arglist)) + if (any_template_arguments_need_structural_equality_p (arglist)) + /* Some of the template arguments require structural + equality testing, so this template class requires + structural equality testing. Note that we check this + condition first because for dependent types that are + created /during/ the parsing of template parameter lists, + we must not require canonical type equality because + canonical types of dependent types are actually going + to be properly computed right at /the end/ of the + template parms parsing. */ + SET_TYPE_STRUCTURAL_EQUALITY (t); + else if (comp_template_args (CLASSTYPE_TI_ARGS (template_type), arglist)) /* This instantiation is another name for the primary template type. Set the TYPE_CANONICAL field appropriately. */ TYPE_CANONICAL (t) = template_type; - else if (any_template_arguments_need_structural_equality_p (arglist)) - /* Some of the template arguments require structural - equality testing, so this template class requires - structural equality testing. */ - SET_TYPE_STRUCTURAL_EQUALITY (t); } /* If we called start_enum or pushtag above, this information @@ -8722,6 +8901,7 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) { tree r = NULL_TREE; tree* new_parms; + bool reduce_level_p = !(complain & tf_no_tpl_reduce); /* When substituting into a template, we must set PROCESSING_TEMPLATE_DECL as the template parameters may be @@ -8730,19 +8910,18 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) ++processing_template_decl; for (new_parms = &r; - TMPL_PARMS_DEPTH (parms) > TMPL_ARGS_DEPTH (args); + ((reduce_level_p && TMPL_PARMS_DEPTH (parms) > TMPL_ARGS_DEPTH (args)) + ||(!reduce_level_p && parms)); new_parms = &(TREE_CHAIN (*new_parms)), parms = TREE_CHAIN (parms)) { tree new_vec = make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms))); - int i; + int i, new_level; for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i) { tree tuple; - tree default_value; - tree parm_decl; if (parms == error_mark_node) continue; @@ -8752,23 +8931,16 @@ 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_level = reduce_level_p + ? TMPL_PARMS_DEPTH (parms) - TMPL_ARGS_DEPTH (args) + : TMPL_PARMS_DEPTH (parms); + *new_parms = - tree_cons (size_int (TMPL_PARMS_DEPTH (parms) - - TMPL_ARGS_DEPTH (args)), + tree_cons (size_int (new_level), new_vec, NULL_TREE); } @@ -8777,6 +8949,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 @@ -10271,9 +10473,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) else { r = copy_type (t); - TEMPLATE_TYPE_PARM_INDEX (r) - = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t), - r, levels, args, complain); + if (!(complain & tf_no_tpl_reduce)) + TEMPLATE_TYPE_PARM_INDEX (r) + = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t), + r, levels, args, complain); TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r); TYPE_MAIN_VARIANT (r) = r; TYPE_POINTER_TO (r) = NULL_TREE; @@ -10291,7 +10494,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) else if (TYPE_STRUCTURAL_EQUALITY_P (t)) SET_TYPE_STRUCTURAL_EQUALITY (r); else - TYPE_CANONICAL (r) = canonical_type_parameter (r); + { + unsigned num_parms = + (TEMPLATE_NUM_SIBLING_PARMS (t)) + ? TREE_INT_CST_LOW (TEMPLATE_NUM_SIBLING_PARMS (t)) + : 0; + TYPE_CANONICAL (r) = + canonical_type_parameter (r, num_parms); + } if (code == BOUND_TEMPLATE_TEMPLATE_PARM) { @@ -10307,7 +10517,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) break; case TEMPLATE_PARM_INDEX: - r = reduce_template_parm_level (t, type, levels, args, complain); + if (complain & tf_no_tpl_reduce) + r = t; + else + r = reduce_template_parm_level (t, type, levels, args, complain); break; default: @@ -17786,7 +17999,8 @@ type_dependent_expression_p (tree expression) if (!processing_template_decl) return false; - if (expression == error_mark_node) + if (expression == error_mark_node + || expression == NULL_TREE) return false; /* An unresolved name is always dependent. */ @@ -18406,7 +18620,7 @@ make_auto (void) TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index (0, processing_template_decl + 1, processing_template_decl + 1, TYPE_NAME (au), NULL_TREE); - TYPE_CANONICAL (au) = canonical_type_parameter (au); + TYPE_CANONICAL (au) = canonical_type_parameter (au, 0); 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 ea01d1f..580ebf3 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1063,22 +1063,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 0ac95d0..41aaca7 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1143,114 +1143,20 @@ comp_template_parms_position (tree t1, tree t2) || 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); - - /* 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_NUM_SIBLING_PARMS (TYPE_MAIN_VARIANT (t1)) + != TEMPLATE_NUM_SIBLING_PARMS (TYPE_MAIN_VARIANT (t2))) 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_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; - /* And now compare the mighty template parms! */ - return !comp_template_parms (tparms1, tparms2); + return true; } /* Subroutine in comptypes. */ @@ -1295,12 +1201,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). */ @@ -1345,6 +1245,7 @@ structural_comptypes (tree t1, tree t2, int strict) (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)), DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)))) return false; + if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM) break; /* Don't check inheritance. */ @@ -1401,8 +1302,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/typedef36.C b/gcc/testsuite/g++.dg/template/typedef36.C new file mode 100644 index 0000000..f6155c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef36.C @@ -0,0 +1,23 @@ +// Origin: PR c++/45606 +// { dg-do compile } + +#include + +template +class Test +{ +protected: + typedef std::list ListAlias; + ListAlias list; +public: + typedef typename ListAlias::const_iterator const_iterator; + inline const_iterator begin() const; + +}; + +template +inline typename std::list::const_iterator Test::begin() const +{ + return list.begin(); +} +