From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20296 invoked by alias); 8 Mar 2012 13:22:19 -0000 Received: (qmail 20269 invoked by uid 22791); 8 Mar 2012 13:22:07 -0000 X-SWARE-Spam-Status: No, hits=-6.2 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_FN,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; Thu, 08 Mar 2012 13:21:18 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q28DLHNC002211 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 8 Mar 2012 08:21:18 -0500 Received: from localhost (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q28DLFbf020604 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 8 Mar 2012 08:21:16 -0500 Received: by localhost (Postfix, from userid 500) id 1B17D29C068; Thu, 8 Mar 2012 14:21:15 +0100 (CET) From: Dodji Seketeli To: Jason Merrill Cc: GCC Patches Subject: Re: [PATCH] PR c++/50852 - Revisit dependant template parameter References: <4F15C5D8.9030306@redhat.com> <4F21C8D1.5070205@redhat.com> X-URL: http://www.redhat.com Date: Thu, 08 Mar 2012 13:22:00 -0000 In-Reply-To: <4F21C8D1.5070205@redhat.com> (Jason Merrill's message of "Thu, 26 Jan 2012 16:42:41 -0500") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii 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: 2012-03/txt/msg00559.txt.bz2 Hello, After we discussed a little bit offline about this, I went forward and updated the patch. Just to recap, the idea of the patch is to make each TEMPLATE_TYPE_INDEX have a pointer to the siblings of its level and consider those siblings during dependant type comparison. This has 2 main implications. 1/ When comparing siblings of a given template parameter type, we must avoid recurring into comparing those siblings again, by fear of and endless recursion. 2/ We must pay some attention in the context of partial instantiation of member templates. For instance: template // The level of T here is 1. struct S { template struct M {}; //The level of U here is 2. }; If we look at S::M, we are partially instantiating M with the set of arguments {int} (of depth 1) when M would need a set of argument of depth 2 to be fully instantiated. In that context, the level of template S::M is no more 2, but rather 1. We say that U has been level-reduced. When a template parameter type T is level-reduced to a type Tr, the siblings pointed to by the TEMPLATE_TYPE_INDEX of Tr needs to be updated to the new siblings parameters, and Tr needs to fixed-up to compute its new canonical type. Point 1/ was already addressed in the previous iteration of this patch. This patch amended it to avoid using *_real function names in the public API. Point 2/ is mostly what this patch is about and during that journey, I came across a number of roadblocks that I think are worth presenting in English in order to share a high level understanding of what the patch does. [Fix-up level-reduced parms in template header *and* in its body] A main difference between fixing up types during the initial parsing and after level-reduction is that in the later case, we need to update references to the pre-fix-up type in the pattern of the template so that they point to the fixed-up type. To be able to do this, the plan I came up with is: 2.1/ Make tsubst_template_parms fix up the template parm types that have been level reduced. This amounts to doing the fix-up in the template header. 2.2/ In tsubst_decl, for TEMPLATE_DECL, (this is a context that can trigger partial instantiation of a member template) call tsubst_template_parms upfront; that is, before anything else. At this point, the level-reduced parm types are fixed-up in the template header. 2.3/ Then I tried to arrange for this: if we ever fix up a template parm type T that is the result of level-reducing a parm type T_ORIG to level L, any subsequent attempt to level-reduce T_ORIG to level L should yield T, thus doing away with the need of fixing up the result of subsequent level-reducing T_ORIG to level L. This appeared to be enough to propagate the fixed-up level-reduced type (that got fixed-up in template headers in 2.2) into the pattern of a the template - using tsubsting that triggers level-reducing there. This takes changing the format of TEMPLATE_PARM_DESCENDANTS of the T_ORIG to make it roughly contain a TREE_VEC in which each index is a level an the element is the fixed-up type (rather, the fixed-up TEMPLATE_PARM_INDEX) for that level. I had to adapt that a little bit to introduce a concept similar to canonical types for TEMPLATE_PARM_INDEXes; it is useful because it appeared that several different pointers to TEMPLATE_PARM_INDEXes can require to be considered equivalent. 2.4/ Do 2.2 in contexts (other than tsubst_decl) that can trigger partial instantiation of member templates. That is, in instantiate_class_template_1, tsubst_aggr_type and tsubst (for the UNBOUND_CLASS_TEMPLATE case). [Make friend TYPENAME_TYPE nodes carry a TEMPLATE_DECL when necessary] It appeared that I couldn't get a handle on the list of template parameters used in friend declarations like this one: template struct S0 { struct F {}; }; template struct S1 { template friend SO::F; //#1 }; During partial instantiation of the declaration #1, there was no way I could access the TEMPLATE_DECL for the TYPENAME_TYPE SO::F because it is just not created; so I couldn't get the parms of that TEMPLATE_DECL either, and I couldn't in turn fix up the U in S0. So I changed the parser to create a TEMPLATE_DECL node in this case. [Handle fix-up for level-reduced a template parameter pack] This one confused me quite a little bit. Consider the test gcc/testsuite/g++.dg/cpp0x/variadic120.C: template struct tuple; template struct tuple { T t; }; template struct pair; template<> struct pair { }; template struct A { template ...> > static void f() { V v; } }; int main() { A::f(); } In the partial instantiation of the member template A::f, the level of the parameter pack Us is NOT reduced, even if it ought to be considered as morally reduced. What happens instead is that the pack expansion tuple... remembers the argument list {int}, without changing the level of Us. Later, when we consider A::f, the pack expansion has enough arguments ({int, double}) to be properly instantiated. This is all fine but it caused me some headaches in tsubst_pack_expansion. Let's call Us' the morally reduced version of Us. Us' and Us look exactly the same, even though they belong to different template levels. To tell them apart one needs to look at the pack expansion they are part of, to see if it is remembering a set of arguments or not; like the way tuple... remembers {int} above, during the partial instantiation of template f. So let's say we fix up Us'. In the process of that fix-up, arg_from_parm_pack_p cannot detect that the pre-fix-up Us' is equivalent to the post-fix-up Us'. It can't even make the difference between Us and Us'. So tsubst_pack_expansion would yield a bogus results on that pack expansion, and that bogus result will go unnoticed until very late in the deduction process leading to issues which root cause is hard top spot - at least for me. So I came up with a new function arg_from_reduced_and_fixedup_parm_pack_of_expansion_p that takes the pack expansion in consideration when comparing pre-fix-up Us' and post-fix-up Us'. It is not perfect as it only look if the levels and tree code match. I believe that to make it perfect, I would need to add a pointer to TEMPLATE_PARM_INDEX to track the pre-fix-up type it was built from; this pointer would be updated by the fix-up code. The problem is that it would increase the size of TEMPLATE_PARM_INDEX even more. So I welcome your input. [Fix partial instantiation in get_mostly_instantiated_function_type] In this function, it appeared that we were triggering something like a partial instantiation but not quite; the substituting was being done with a full set of N arguments which last P elements were put to NULL_TREE (instead of having a set N-P arguments) tsubst was triggering a level-reduction of some template parameters, the level-reduced parms would have a level of zero. Which violates the constraint that levels should be at least 1. The patch fixes that. Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk. gcc/cp/ PR c++/50852 * cp-tree.h (struct template_parm_index_s): Remove. (struct template_parm_index_s): New members. (COMPARE_NO_SIBLINGS): New type comparison control flag. (TEMPLATE_PARM_SIBLINGS): New accessor macro. (TEMPLATE_PARM_DESCENDANTS): Add comments. (TEMPLATE_PARM_ORIG_INDEX): New accessor. (TEMPLATE_PARM_ORIG_LEVEL): Rewrite in terms of TEMPLATE_PARM_ORIG_INDEX. (process_template_parm): Change the integer num_siblings parm into a tree siblings parm. (comp_template_parms_siblings, comp_template_parm_levels) (comp_template_parms_guided, comp_template_args_guided) (same_type_ignoring_top_level_qualifiers_guided_p, compare_trees) (template_type_parameter_type_p): Declare new functions. (fixup_current_template_parms): New, better name for fixup_template_parms. (fixup_template_parms): Take the set of parameters to fixup in parameters. * pt.c (arg_from_reduced_and_fixedup_parm_pack_of_expansion_p) (get_root_index_same_level) (get_template_parameter_level_and_index) (add_descendant_to_parm_index, get_descendant_of_parm_index) (get_template_parm_index, comp_template_parm_levels) (template_parms_to_args, template_type_parameter_type_p): Define new functions. (current_template_args): Use the new template_parms_to_args function. (fixup_template_type_parm_type) (fixup_template_parm_index, build_template_parm_index) (fixup_template_parm_index, process_template_parm) (fixup_template_type_parm_type, fixup_template_parm) (process_template_parm): Change the integer num_siblings parm into a tree siblings parm. Update comments. (build_template_parm_index): Likewise. Replace ORIG_LEVEL integer parm with an ORIG_INDEX tree. Add a few asserts. (get_template_info): Make this more robust and support getting template info from TYPENAME_TYPE nodes. (comp_template_parms_guided): New function. Takes an additional parm to control comparison. Factorized out of ... (comp_template_parms): ... this. (reduce_template_parm_level): Use TEMPLATE_PARM_SIBLINGS instead of TEMPLATE_PARM_NUM_SIBLINGS. Update usage of TEMPLATE_PARM_DESCENDANTS. Use the new get_descendant_of_parm_index. (template_args_equal_guided): Take an additional parm to control comparison. Use template_args_equal_guided instead of template_args_equal. Factorize this out of ... (template_args_equal): ... this. (comp_template_args_guided): Take an additional parm to control comparison. Renamed from comp_template_args_with_info. Make this public. (comp_template_args, unify_pack_expansion): Adjust. (fixup_innermost_template_parms): Transformed former fixup_template_parms in to this. Make it take a set of parms to fixup and an arglist. Update comments. (fixup_template_parms): Take the parms to fixup in argument. (fixup_current_template_parms): This is the new name for the former fixup_template_parms. It has be re-written in terms of fixup_innermost_template_parms. * tree.c (compare_trees): Factorized this out of cp_tree_equal. Take a comparison control parameter. Use tree comparison functions that take a comparison control parm. (cp_tree_equal): Use the factorized compare_trees. (tsubst_template_parms): Fixup template parameters that are level-reduced. (push_template_decl_real): Support declarations of friend template represented by TYPENAME_TYPE nodes. (instantiate_class_template_1, tsubst_aggr_type, tsubst_decl) (tsubst): Call tsubst_template_parms upfront to fixup dependant types that are to be level-reduced by a possible partial instantiation of a member template. (tsubst_pack_expansion): During type fixup, take in account parm packs that have been level-reduced. (get_mostly_instantiated_function_type): Fix this by setting the proper size for the args of tsubst, so that partial instantiation happens there. Otherwise, tsubst indirectly and wrongly calls reduce_template_parm_level with a reduced level of 0. (make_auto): Adjust for sibling_parms instead of num_sibling_parms. * typeck.c (compparms_guided): Take a comparison control parameter. Split out of ... (compparms): ... this. (comp_template_parms_siblings): Define new function. (comp_template_parms_position): Take an additional parameter to control the comparison. Use the new comp_template_parms_siblings. (structural_comptypes): Use type comparison routines variants that take the comparison control parm. (same_type_ignoring_top_level_qualifiers_guided_p): Take an additional parm to control comparison. Use comptypes instead of comptypes. Factorize out of ... (same_type_ignoring_top_level_qualifiers_p): ... this. * parser.c (cp_parser_template_parameter_list): Adjust for the change to using sibling_parms instead of num_sibling_parms. (cp_parser_template_declaration_after_export): Adjust to call fixup_current_template_parms instead of fixup_template_parms. (cp_parser_single_declaration): Make friend typename declarations carry a template info. gcc/testsuite/ PR c++/50852 * g++.dg/template/typedef39.C: New test. * g++.dg/template/typedef40.C: Likewise. * g++.dg/template/typedef41.C: Likewise. * g++.dg/template/crash84.C: This test should actually pass without error. --- gcc/cp/cp-tree.h | 94 +++- gcc/cp/parser.c | 21 +- gcc/cp/pt.c | 973 +++++++++++++++++++++++------ gcc/cp/tree.c | 115 ++-- gcc/cp/typeck.c | 162 ++++-- gcc/testsuite/g++.dg/template/crash84.C | 8 +- gcc/testsuite/g++.dg/template/typedef39.C | 16 + gcc/testsuite/g++.dg/template/typedef40.C | 22 + gcc/testsuite/g++.dg/template/typedef41.C | 19 + 9 files changed, 1134 insertions(+), 296 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/typedef39.C create mode 100644 gcc/testsuite/g++.dg/template/typedef40.C create mode 100644 gcc/testsuite/g++.dg/template/typedef41.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 71573ff..4e4aaec 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -247,8 +247,12 @@ struct GTY(()) template_parm_index_s { struct tree_common common; int index; int level; - int orig_level; - int num_siblings; + /* If the current index was reduced from an original index, keep + track of the later using this pointer. */ + tree orig_index; + /* A TREE_VEC containing the set of parms this parameter belongs + to. */ + tree siblings; tree decl; }; typedef struct template_parm_index_s template_parm_index; @@ -4476,6 +4480,9 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; structural. The actual comparison will be identical to COMPARE_STRICT. */ +#define COMPARE_NO_SIBLINGS 16 /* When comparing template + parameters, don't consider their + siblings. */ /* Used with push_overloaded_decl. */ #define PUSH_GLOBAL 0 /* Push the DECL into namespace scope, @@ -4509,11 +4516,69 @@ 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) +/* A TREE_VEC containing the sibling parameters for a given template + parm. */ +#define TEMPLATE_PARM_SIBLINGS(NODE) \ + (TEMPLATE_PARM_INDEX_CAST (NODE)->siblings) + +/* This accessor has to do with partial instantiation of member + templates and type fixup. + + Consider the member template M below: + + template + struct S + { + template struct M {}; + }; + + When we say template S::M, M is partially + instantiated and the level of its template parameter V is reduced; + it was 2 initially, but in the context of the partial + instantiation, it becomes 1. + + TEMPLATE_PARM_DESCENDANTS for U captures the relationship between that + parameter and those that result from its level-reducing. + + For template type parameters, TEMPLATE_PARM_DESCENDANTS is a vector + in which each element represents a parameter reduced to a level + that is the vector index of said element. In the example above, + the element at index 1 of TEMPLATE_PARM_DESCENDANTS (U) will + contain V. + + For non-type template parameters, TEMPLATE_PARM_DESCENDANTS is a + vector or TREE_LIST. For a given level (that represents the index + of each element of the vector), there is a list of parameters + reduced to that level, and each parameter of that list has a + different type. For instance: + + template + struct S + { + template struct M {}; + }; + + When we say template<> S::M, the level of parameter 'a' is + reduced to 1 (from 2), and its type is 'int'. + + When we say template<> S::M, the level of 'a' is reduced to 1 + as well, but its type is 'char'. + + So in TEMPLATE_PARM_DESCENDANTS for parameter 'a', the element at + index 1 will be a TREE_LIST of two elements which first TREE_VALUE + is the TEMPLATE_PARM_INDEX for 'int a' and which second TREE_VALUE + is the TEMPLATE_PARM_INDEX for 'char a'. + + Note that types of template parameters that are inserted into + TEMPLATE_PARM_DESCENDANTS are always fixed-up types. + + Also note that the argument for TEMPLATE_PARM_DESCENDANT must be a + TEMPLATE_PARM_INDEX. */ +#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (TEMPLATE_PARM_INDEX_CHECK (NODE))) +#define TEMPLATE_PARM_ORIG_INDEX(NODE) \ + (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_index) +#define TEMPLATE_PARM_ORIG_LEVEL(NODE) \ + (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (NODE))) #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl) #define TEMPLATE_PARM_PARAMETER_PACK(NODE) \ (TREE_LANG_FLAG_0 (TEMPLATE_PARM_INDEX_CHECK (NODE))) @@ -5280,9 +5345,10 @@ 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, unsigned); + bool, bool, tree); extern tree end_template_parm_list (tree); -void fixup_template_parms (void); +extern void fixup_current_template_parms (void); +extern void fixup_template_parms (tree); extern void end_template_decl (void); extern tree maybe_update_decl_type (tree, tree); extern bool check_default_tmpl_args (tree, tree, int, int, int); @@ -5307,8 +5373,12 @@ extern void do_type_instantiation (tree, tree, tsubst_flags_t); extern bool always_instantiate_p (tree); extern void maybe_instantiate_noexcept (tree); extern tree instantiate_decl (tree, int, bool); +extern bool comp_template_parms_siblings (tree, tree, int); +extern int comp_template_parm_levels (const_tree, const_tree, int); +extern int comp_template_parms_guided (const_tree, const_tree, int); extern int comp_template_parms (const_tree, const_tree); extern bool uses_parameter_packs (tree); +extern bool template_type_parameter_type_p (tree); extern bool template_parameter_pack_p (const_tree); extern bool function_parameter_pack_p (const_tree); extern bool function_parameter_expanded_from_pack_p (tree, tree); @@ -5321,6 +5391,8 @@ extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); extern bool is_specialization_of_friend (tree, tree); extern tree get_pattern_parm (tree, tree); +extern int comp_template_args_guided (tree, tree, tree *, + tree *, int); extern int comp_template_args (tree, tree); extern tree maybe_process_partial_specialization (tree); extern tree most_specialized_instantiation (tree); @@ -5700,6 +5772,7 @@ extern tree lvalue_type (tree); extern tree error_type (tree); extern int varargs_function_p (const_tree); extern bool really_overloaded_fn (tree); +extern bool compare_trees (tree, tree, int); extern bool cp_tree_equal (tree, tree); extern tree no_linkage_check (tree, bool); extern void debug_binfo (tree); @@ -5760,6 +5833,9 @@ extern int type_unknown_p (const_tree); enum { ce_derived, ce_normal, ce_exact }; extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); +extern bool same_type_ignoring_top_level_qualifiers_guided_p (tree type1, + tree type2, + int strict); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); extern bool compparms (const_tree, const_tree); extern int comp_cv_qualification (const_tree, const_tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c6bd290..37e82a9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11960,7 +11960,7 @@ cp_parser_template_parameter_list (cp_parser* parser) parameter, is_non_type, is_parameter_pack, - 0); + NULL_TREE); else { tree err_parm = build_tree_list (parameter, parameter); @@ -21124,7 +21124,7 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) { /* Parse the template parameters. */ parameter_list = cp_parser_template_parameter_list (parser); - fixup_template_parms (); + fixup_current_template_parms (); } /* Get the deferred access checks from the parameter list. These @@ -21289,6 +21289,7 @@ cp_parser_single_declaration (cp_parser* parser, { if (cp_parser_declares_only_class_p (parser)) { + bool friend_typename_p = false; decl = shadow_tag (&decl_specifiers); /* In this case: @@ -21303,7 +21304,10 @@ cp_parser_single_declaration (cp_parser* parser, && !decl && decl_specifiers.type && TYPE_P (decl_specifiers.type)) - decl = decl_specifiers.type; + { + decl = decl_specifiers.type; + friend_typename_p = true; + } if (decl && decl != error_mark_node) decl = TYPE_NAME (decl); @@ -21312,6 +21316,17 @@ cp_parser_single_declaration (cp_parser* parser, /* Perform access checks for template parameters. */ cp_parser_perform_template_parameter_access_checks (checks); + if (friend_typename_p + && parser->num_template_parameter_lists > 0 + && decl != error_mark_node) + /* We are looking a the declaration of a class/enum which + name is a typename; that declaration has a template + header that declares some template parameters used in + the declaration. Ensure the declaration carries a + template info representing that header. That template + info will later be useful when we need to fixup the + template parameters used in the declaration. */ + push_template_decl_real (decl, /*is_friend=*/true); } } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4980c19..51803fe 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -148,7 +148,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, int, tree, tree); +static tree build_template_parm_index (int, int, tree, tree, tree, tree); static bool inline_needs_template_parms (tree); static void push_inline_template_parms_recursive (tree, int); static tree retrieve_local_specialization (tree); @@ -183,6 +183,7 @@ static tree try_class_unification (tree, tree, tree, tree, bool); static int coerce_template_template_parms (tree, tree, tsubst_flags_t, tree, tree); static bool template_template_parm_bindings_ok_p (tree, tree); +static int template_args_equal_guided (tree, tree, int); static int template_args_equal (tree, tree); static void tsubst_default_arguments (tree); static tree for_each_template_parm_r (tree *, int *, void *); @@ -201,12 +202,22 @@ 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 template_parm_to_arg (tree); +static tree template_parms_to_args (tree); static bool arg_from_parm_pack_p (tree, tree); +static bool arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (tree, + tree, + tree); 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 tree get_root_index_same_level (tree); +static void get_template_parameter_level_and_index (tree, int*, int*); +static void add_descendant_to_parm_index (tree, tree); +static tree get_descendant_of_parm_index (tree, int, tree); +static tree get_template_parm_index (tree); +static tree fixup_template_type_parm_type (tree, tree); +static tree fixup_template_parm_index (tree, tree, tree); static tree tsubst_template_parm (tree, tree, tsubst_flags_t); +static void fixup_innermost_template_parms (tree, tree); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function @@ -322,7 +333,16 @@ get_template_info (const_tree t) return NULL; if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) - tinfo = DECL_TEMPLATE_INFO (t); + { + int code = TREE_CODE (t); + /* Only the DECLs below are allowed to have template info. */ + if (code == VAR_DECL + || code == FIELD_DECL + || code == FUNCTION_DECL + || code == TYPE_DECL + || code == TEMPLATE_DECL) + tinfo = DECL_TEMPLATE_INFO (t); + } if (!tinfo && DECL_IMPLICIT_TYPEDEF_P (t)) t = TREE_TYPE (t); @@ -331,6 +351,9 @@ get_template_info (const_tree t) tinfo = TYPE_TEMPLATE_INFO (t); else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM) tinfo = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t); + else if (TREE_CODE (t) == TYPENAME_TYPE + && DECL_LANG_SPECIFIC (TYPE_NAME (t))) + tinfo = DECL_TEMPLATE_INFO (TYPE_NAME (t)); return tinfo; } @@ -2675,11 +2698,56 @@ check_explicit_specialization (tree declarator, } /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template + parameters of a given level, represented by a TREE_VEC of + TREE_LIST. The TREE_VALUE of each TREE_LIST represents a given + template parameter. STRICT controls how the comparison is done. + It has the same meaning as the last parameter of the comptypes + function. */ + +int +comp_template_parm_levels (const_tree parms_level1, + const_tree parms_level2, + int strict) +{ + int i; + gcc_assert (TREE_CODE (parms_level1) == TREE_VEC); + gcc_assert (TREE_CODE (parms_level2) == TREE_VEC); + + if (TREE_VEC_LENGTH (parms_level1) != TREE_VEC_LENGTH (parms_level2)) + return 0; + + for (i = 0; i < TREE_VEC_LENGTH (parms_level2); ++i) + { + tree parm1 = TREE_VALUE (TREE_VEC_ELT (parms_level1, i)); + tree parm2 = TREE_VALUE (TREE_VEC_ELT (parms_level2, i)); + + /* If either of the template parameters are invalid, assume + they match for the sake of error recovery. */ + if (parm1 == error_mark_node || parm2 == error_mark_node) + return 1; + + if (TREE_CODE (parm1) != TREE_CODE (parm2)) + return 0; + + if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM + && (TEMPLATE_TYPE_PARAMETER_PACK (parm1) + == TEMPLATE_TYPE_PARAMETER_PACK (parm2))) + continue; + else if (!comptypes (TREE_TYPE (parm1), TREE_TYPE (parm2), strict)) + return 0; + } + return 1; +} + +/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template parameters. These are represented in the same format used for - DECL_TEMPLATE_PARMS. */ + DECL_TEMPLATE_PARMS. STRICT controls how the comparison is done. + Its semantics are the same as the last parameter of comptypes. */ int -comp_template_parms (const_tree parms1, const_tree parms2) +comp_template_parms_guided (const_tree parms1, + const_tree parms2, + int strict) { const_tree p1; const_tree p2; @@ -2693,34 +2761,9 @@ comp_template_parms (const_tree parms1, const_tree parms2) { tree t1 = TREE_VALUE (p1); tree t2 = TREE_VALUE (p2); - int i; - - gcc_assert (TREE_CODE (t1) == TREE_VEC); - gcc_assert (TREE_CODE (t2) == TREE_VEC); - if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) + if (!comp_template_parm_levels (t1, t2, strict)) return 0; - - for (i = 0; i < TREE_VEC_LENGTH (t2); ++i) - { - tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i)); - tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i)); - - /* If either of the template parameters are invalid, assume - they match for the sake of error recovery. */ - if (parm1 == error_mark_node || parm2 == error_mark_node) - return 1; - - if (TREE_CODE (parm1) != TREE_CODE (parm2)) - return 0; - - if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM - && (TEMPLATE_TYPE_PARAMETER_PACK (parm1) - == TEMPLATE_TYPE_PARAMETER_PACK (parm2))) - continue; - else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2))) - return 0; - } } if ((p1 != NULL_TREE) != (p2 != NULL_TREE)) @@ -2731,6 +2774,28 @@ comp_template_parms (const_tree parms1, const_tree parms2) return 1; } +/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template + parameters. These are represented in the same format used for + DECL_TEMPLATE_PARMS. */ + +int +comp_template_parms (const_tree parms1, const_tree parms2) +{ + return comp_template_parms_guided (parms1, parms2, + COMPARE_STRICT); +} + +/* Determine wheter PARM is the type of a template type parameter. */ + +bool +template_type_parameter_type_p (tree t) +{ + return (t + && (TREE_CODE (t) == TEMPLATE_TYPE_PARM + || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM + || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)); +} + /* Determine whether PARM is a parameter pack. */ bool @@ -3395,22 +3460,27 @@ check_template_shadow (tree decl) } /* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL, - ORIG_LEVEL, DECL, and TYPE. NUM_SIBLINGS is the total number of - template parameters. */ + ORIG_INDEX, DECL, and TYPE. SIBLINGS is a TREE_VEC containing the + set of parameters the current template parameter belongs to. */ static tree build_template_parm_index (int index, int level, - int orig_level, - int num_siblings, + tree orig_index, + tree siblings, tree decl, tree type) { - tree t = make_node (TEMPLATE_PARM_INDEX); + tree t; + + gcc_assert (level >= 1); + + t = make_node (TEMPLATE_PARM_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_ORIG_INDEX (t) = orig_index ? orig_index : t; + gcc_assert (TREE_CODE (TEMPLATE_PARM_ORIG_INDEX (t)) == TEMPLATE_PARM_INDEX); + TEMPLATE_PARM_SIBLINGS (t) = siblings; TEMPLATE_PARM_DECL (t) = decl; TREE_TYPE (t) = type; TREE_CONSTANT (t) = TREE_CONSTANT (decl); @@ -3458,13 +3528,15 @@ static tree reduce_template_parm_level (tree index, tree type, int levels, tree args, tsubst_flags_t complain) { - if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE - || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index)) - != TEMPLATE_PARM_LEVEL (index) - levels) - || !same_type_p (type, TREE_TYPE (TEMPLATE_PARM_DESCENDANTS (index)))) + int new_level = TEMPLATE_PARM_LEVEL (index) - levels; + tree t = NULL_TREE; + + gcc_assert (new_level > 0); + + if ((t = get_descendant_of_parm_index (index, new_level, type)) == NULL_TREE) { tree orig_decl = TEMPLATE_PARM_DECL (index); - tree decl, t; + tree decl; decl = build_decl (DECL_SOURCE_LOCATION (orig_decl), TREE_CODE (orig_decl), DECL_NAME (orig_decl), type); @@ -3475,10 +3547,18 @@ 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), + TEMPLATE_PARM_ORIG_INDEX (index), + /*we will fixup the siblings for + this index in + tsubst_template_parms, so set + it to NULL here. */ + NULL_TREE, decl, type); - TEMPLATE_PARM_DESCENDANTS (index) = t; + /* Do not yet update TEMPLATE_PARM_DESCENDANTS + (TEMPLATE_PARM_ORIG_INDEX (index)) because it will be done + when the new parm index T is fixed up, along with its + siblings, using a call to add_descendant_to_parm_index. */ + TEMPLATE_PARM_PARAMETER_PACK (t) = TEMPLATE_PARM_PARAMETER_PACK (index); @@ -3489,23 +3569,23 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args, args, complain); } - return TEMPLATE_PARM_DESCENDANTS (index); + return t; } /* 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 + is in PARM_LOC. SIBLING_PARMS is a TREE_VEC containing the set of + template parameters 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. */ + iff PARM is a type. If the set of parameters is not known, this + parameter shall be set to NULL_TREE. */ tree process_template_parm (tree list, location_t parm_loc, tree parm, bool is_non_type, bool is_parameter_pack, - unsigned num_template_parms) + tree sibling_parms) { tree decl = 0; tree defval; @@ -3579,8 +3659,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm, TREE_READONLY (decl) = 1; DECL_INITIAL (parm) = DECL_INITIAL (decl) = build_template_parm_index (idx, processing_template_decl, - processing_template_decl, - num_template_parms, + NULL_TREE, + sibling_parms, decl, TREE_TYPE (parm)); TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) @@ -3613,8 +3693,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm, parm = decl; TEMPLATE_TYPE_PARM_INDEX (t) = build_template_parm_index (idx, processing_template_decl, - processing_template_decl, - num_template_parms, + NULL_TREE, + sibling_parms, decl, TREE_TYPE (parm)); TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack; TYPE_CANONICAL (t) = canonical_type_parameter (t); @@ -3654,34 +3734,314 @@ end_template_parm_list (tree parms) return saved_parmlist; } +/* Get the "canonical" INDEX of a given TEMPLATE_PARM_INDEX tree + node. + + There can be several equivalent TEMPLATE_PARM_INDEX created for a + given template parameter, be it a type or non-type template + parameter. + + For a type template parameter P, this function returns the + TEMPLATE_PARM_INDEX of the canonical type of P. + + For a non-type template parameter P, this function returns the + the "original" TEMPLATE_PARM_INDEX P was created from, given that + they both have the same level. */ + +static tree +get_root_index_same_level (tree index) +{ + tree i = index; + + if (TREE_CODE (TEMPLATE_PARM_DECL (i)) == CONST_DECL) + { + if (TEMPLATE_PARM_ORIG_LEVEL (i) == TEMPLATE_PARM_LEVEL (index)) + i = TEMPLATE_PARM_ORIG_INDEX (i); + } + else + { + if (template_type_parameter_type_p (TREE_TYPE (i)) + && TREE_CODE (TEMPLATE_PARM_DECL (i)) != CONST_DECL + && TYPE_CANONICAL (TREE_TYPE (i)) != NULL_TREE) + i = TEMPLATE_TYPE_PARM_INDEX (TYPE_CANONICAL (TREE_TYPE (i))); + } + return i; +} + +/* Get the level and the index of a given template parameter. */ + +static void +get_template_parameter_level_and_index (tree parameter, int *level, int *index) +{ + int l = 0, i = -1; + tree parm; + + if (TREE_CODE (parameter) == TYPE_DECL + || TREE_CODE (parameter) == TEMPLATE_DECL) + parm = TREE_TYPE (parameter); + else if (TREE_CODE (parameter) == PARM_DECL) + parm = DECL_INITIAL (parameter); + else + parm = parameter; + + template_parm_level_and_index (parm, &l, &i); + + gcc_assert (l > 0 && i >= 0); + + if (level) + *level = l; + if (index) + *index = i; +} + +/* Add a descendant to a given template parameter index INDEX. A + descendant of INDEX is the result of reducing the level of INDEX + to another level. The property TEMPLATE_PARM_DESCENDANT of INDEX + is a vector that contains the descendants of INDEX. This function + properly appends the descender of INDEX to that + TEMPLATE_PARM_DESCENDANT vector. */ + +static void +add_descendant_to_parm_index (tree index, + tree descendant) +{ + tree *where = NULL; + + gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX + && TREE_CODE (descendant) == TEMPLATE_PARM_INDEX + && TEMPLATE_PARM_LEVEL (descendant) > 0 + && TEMPLATE_PARM_LEVEL (index) > 0 + && TEMPLATE_PARM_LEVEL (descendant) <= TEMPLATE_PARM_LEVEL (index)); + + if (TYPE_CANONICAL (TREE_TYPE (TEMPLATE_PARM_DECL (descendant))) + != NULL_TREE) + /* For a descendant that requires canonical type comparison + (unlike for reduced template template parms) we only accept + types that have been fixed-up. */ + gcc_assert (TEMPLATE_PARM_SIBLINGS (descendant) != NULL_TREE); + + index = get_root_index_same_level (index); + + if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE) + TEMPLATE_PARM_DESCENDANTS (index) = + make_tree_vec (TEMPLATE_PARM_LEVEL (index)); + + where = &TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index), + TEMPLATE_PARM_LEVEL (descendant) - 1); + + if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL) + { + /* INDEX is for a non-type template param. So each one of its + descendant might have a different type. To see that, consider: + + template struct S + { + template class TT> struct Inner; + }; + + Then if we write: + + S s0; + + As a result, in: + + template<> template class TT> + S::Inner + + 'i' has level 2, which was reduced from its inital level 3. + But look at how its type is 'int'. + + But if we write: + + S s1; + + Then, in: + + template<> template class TT> + S::Inner + + 'i' still has level 2 (reduced from initial level 3), but its + type is now 'char'. + + So both 'i' of level 2 that are descendants of the initial + 'i' of level 3, but each of them (might) have a separate + type. + + Therefore, at each index of TEMPLATE_PARM_DESCENDANTS (that + represent a level) we have a TREE_LIST in which each + TREE_PURPOSE has the type of TEMPLATE_PARM_INDEX and each + TREE_VALUE has the TEMPLATE_PARM_INDEX itself. */ + if (*where != NULL_TREE) + gcc_assert (TEMPLATE_PARM_LEVEL (TREE_VALUE (*where)) + == TEMPLATE_PARM_LEVEL (descendant)); + *where = tree_cons (TREE_TYPE (descendant), + descendant, + *where); + } + else + { + if (*where == NULL_TREE) + TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index), + TEMPLATE_PARM_LEVEL (descendant) - 1) = descendant; + else + gcc_assert (same_type_p (TREE_TYPE (*where), + TREE_TYPE (descendant)) + && (TEMPLATE_PARM_LEVEL (*where) + == TEMPLATE_PARM_LEVEL (descendant))); + } +} + +/* Inspect the TEMPLATE_PARM_DESCENDANTS vector associated to INDEX + to return its descendant for a given level and type. */ + +static tree +get_descendant_of_parm_index (tree index, + int level, + tree type) +{ + tree result = NULL_TREE, orig_index = index; + + gcc_assert (TREE_CODE (index) == TEMPLATE_PARM_INDEX + && TEMPLATE_PARM_LEVEL (index) > 0 + && level > 0); + + index = get_root_index_same_level (index); + + if (TEMPLATE_PARM_DESCENDANTS (index)) + { + gcc_assert (TREE_CODE (TEMPLATE_PARM_DESCENDANTS (index)) == TREE_VEC); + if (TREE_VEC_LENGTH (TEMPLATE_PARM_DESCENDANTS (index)) >= level) + { + tree elem = TREE_VEC_ELT (TEMPLATE_PARM_DESCENDANTS (index), + level - 1); + if (TREE_CODE (TEMPLATE_PARM_DECL (index)) == CONST_DECL) + /* We are looking for the index of a non-type template + parm. */ + for (; elem != NULL_TREE; elem = TREE_CHAIN (elem)) + { + if (same_type_p (TREE_TYPE (TREE_VALUE (elem)), + type)) + result = TREE_VALUE (elem); + } + else + /* We are looking for the index of type template parm. */ + result = elem; + if (result != NULL_TREE + && (TEMPLATE_PARM_LEVEL (result) != TEMPLATE_PARM_LEVEL (orig_index)) + && (DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (result)) + != DECL_SOURCE_LOCATION (TEMPLATE_PARM_DECL (orig_index)))) + { + /* We have gotten an equivalent index, that was reduced + from index from ORIG_INDEX, but which (location of) + DECL is different. This can lead to having error + messages pointing to the wrong location, so let's + build an equivalent TEMPLATE_PARM_INDEX with a DECL + pointing to the same location as ORIG_INDEX for + RESULT. */ + tree decl, orig_decl, orig_result = result, decl_type; + + decl = orig_decl = TEMPLATE_PARM_DECL (orig_index); + + if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == CONST_DECL) + { + decl = build_decl (DECL_SOURCE_LOCATION (orig_decl), + TREE_CODE (orig_decl), DECL_NAME (orig_decl), + TREE_TYPE (result)); + TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl); + TREE_READONLY (decl) = TREE_READONLY (orig_decl); + DECL_ARTIFICIAL (decl) = 1; + SET_DECL_TEMPLATE_PARM_P (decl); + + result = build_template_parm_index (TEMPLATE_PARM_IDX (result), + TEMPLATE_PARM_LEVEL (result), + TEMPLATE_PARM_ORIG_INDEX (result), + TEMPLATE_PARM_SIBLINGS (result), + decl, + TREE_TYPE (result)); + TEMPLATE_PARM_PARAMETER_PACK (result) = + TEMPLATE_PARM_PARAMETER_PACK (orig_result); + TEMPLATE_PARM_DESCENDANTS (result) = + TEMPLATE_PARM_DESCENDANTS (orig_result); + + decl_type = copy_type (TREE_TYPE (decl)); + TYPE_NAME (decl_type) = decl; + TREE_TYPE (decl) = decl_type; + TREE_TYPE (result) = decl_type; + } + } + + } + } + return result; +} + +/* Return the TEMPLATE_PARM_INDEX of a template parameter PARM. PARM + can be either the type of a template parameter, or its DECL. */ + +static tree +get_template_parm_index (tree parm) +{ + tree result = NULL_TREE; + + switch (TREE_CODE (parm)) + { + case TEMPLATE_PARM_INDEX: + result = parm; + break; + + case TEMPLATE_TYPE_PARM: + case TEMPLATE_TEMPLATE_PARM: + case BOUND_TEMPLATE_TEMPLATE_PARM: + result = TEMPLATE_TYPE_PARM_INDEX (parm); + break; + + case PARM_DECL: + case CONST_DECL: + gcc_assert (DECL_TEMPLATE_PARM_P (parm)); + return get_template_parm_index (DECL_INITIAL (parm)); + + case TEMPLATE_DECL: + case TYPE_DECL: + gcc_assert (DECL_TEMPLATE_PARM_P (parm)); + return get_template_parm_index (TREE_TYPE (parm)); + + default: + gcc_unreachable (); + } + + return result; +} + /* 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. + 1/ T has a new TEMPLATE_PARM_INDEX that carries the set of + sibling template parameters of T. - 2/ T has a new canonical type that matches the new number - of sibling parms. + 2/ T has a new canonical type that matches the set 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. + name of TYPE will return. No lookup should return TYPE anymore. - NUM_PARMS is the new number of sibling parms TYPE belongs to. + SIBLING_PARMS is the set of sibling parms TYPE belongs to. - This is a subroutine of fixup_template_parms. */ + This is a subroutine of fixup_innermost_template_parms. */ static tree -fixup_template_type_parm_type (tree type, int num_parms) +fixup_template_type_parm_type (tree type, tree sibling_parms) { - tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), idx; - tree t; + tree orig_idx = TEMPLATE_TYPE_PARM_INDEX (type), + t, idx, parent_idx = NULL_TREE; /* 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) + if (orig_idx && TEMPLATE_PARM_SIBLINGS (orig_idx) != NULL_TREE) return type; t = copy_type (type); @@ -3692,12 +4052,19 @@ fixup_template_type_parm_type (tree type, int num_parms) TYPE_POINTER_TO (t) = 0; TYPE_REFERENCE_TO (t) = 0; + if (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (orig_idx)) + != TEMPLATE_PARM_LEVEL (orig_idx)) + /* We are fixing up a type which TEMPLATE_TYPE_PARM_INDEX is the + result of level-reduction. Keep a pointer to the original + upper (fixed-up) level index. */ + parent_idx = TEMPLATE_PARM_ORIG_INDEX (orig_idx); + idx = build_template_parm_index (TEMPLATE_PARM_IDX (orig_idx), TEMPLATE_PARM_LEVEL (orig_idx), - TEMPLATE_PARM_ORIG_LEVEL (orig_idx), - num_parms, + parent_idx, + sibling_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; @@ -3711,7 +4078,15 @@ fixup_template_type_parm_type (tree type, int num_parms) type is properly fixed up. */ TREE_TYPE (decl) = t; - TYPE_CANONICAL (t) = canonical_type_parameter (t); + /* Don't set canonical type if the original type was requiring + structural equality. This can happen for e.g, types of template + template parms that got level-reduced. */ + if (!TYPE_STRUCTURAL_EQUALITY_P (type)) + TYPE_CANONICAL (t) = canonical_type_parameter (t); + + /* Update TEMPLATE_PARM_DESCENDANTS (TEMPLATE_PARM_ORIG_INDEX + (orig_idx)). */ + add_descendant_to_parm_index (TEMPLATE_PARM_ORIG_INDEX (idx), idx); return t; } @@ -3719,35 +4094,41 @@ fixup_template_type_parm_type (tree type, int num_parms) /* 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 + 1/ carry the set of sibling parms (SIBLING_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 + 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. */ + This is a subroutine of fixup_innermost_template_parms. */ static tree -fixup_template_parm_index (tree i, tree args, int num_parms) +fixup_template_parm_index (tree i, tree args, tree sibling_parms) { - tree index, decl, type; + tree index, decl, type, parent_idx = NULL_TREE; if (i == NULL_TREE || TREE_CODE (i) != TEMPLATE_PARM_INDEX /* Do not fix up the index twice. */ - || (TEMPLATE_PARM_NUM_SIBLINGS (i) != 0)) + || (TEMPLATE_PARM_SIBLINGS (i) != NULL_TREE)) return i; decl = TEMPLATE_PARM_DECL (i); type = TREE_TYPE (decl); + if (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_ORIG_INDEX (i)) + != TEMPLATE_PARM_LEVEL (i)) + /* We are fixing up a type which TEMPLATE_TYPE_PARM_INDEX is the + result or a level-reduction. Keep a pointer to the original + upper (fixed-up) level. */ + parent_idx = TEMPLATE_PARM_ORIG_INDEX (i); + index = build_template_parm_index (TEMPLATE_PARM_IDX (i), TEMPLATE_PARM_LEVEL (i), - TEMPLATE_PARM_ORIG_LEVEL (i), - num_parms, + parent_idx, sibling_parms, decl, type); TEMPLATE_PARM_DESCENDANTS (index) = TEMPLATE_PARM_DESCENDANTS (i); @@ -3758,11 +4139,15 @@ fixup_template_parm_index (tree i, tree args, int num_parms) TREE_TYPE (decl) = type; TREE_TYPE (index) = type; + /* Update descendants of the original index INDEX is reduced + from. */ + add_descendant_to_parm_index (TEMPLATE_PARM_ORIG_INDEX (index), + index); return index; } /* - This is a subroutine of fixup_template_parms. + This is a subroutine of fixup_innermost_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 @@ -3770,8 +4155,8 @@ fixup_template_parm_index (tree i, tree args, int num_parms) 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 + the template parameter, starting at 0. SIBLING_PARMS is the set of + template parameters the 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 @@ -3782,11 +4167,18 @@ fixup_template_parm_index (tree i, tree args, int num_parms) static void fixup_template_parm (tree parm_desc, int idx, - int num_parms, + tree sibling_parms, tree arglist) { tree parm = TREE_VALUE (parm_desc); - tree fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist); + tree fixedup_args; + int level; + + if (parm == error_mark_node) + return; + + get_template_parameter_level_and_index (parm, &level, NULL); + fixedup_args = TMPL_ARGS_LEVEL (arglist, level); push_deferring_access_checks (dk_no_check); @@ -3798,7 +4190,7 @@ fixup_template_parm (tree parm_desc, template parms into the default argument of this parameter. */ tree t = - fixup_template_type_parm_type (TREE_TYPE (parm), num_parms); + fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms); TREE_TYPE (parm) = t; TREE_VEC_ELT (fixedup_args, idx) = template_parm_to_arg (parm_desc); @@ -3852,13 +4244,12 @@ fixup_template_parm (tree parm_desc, template_parm_to_arg (parameter); fixup_template_parm (parameter, j, - TREE_VEC_LENGTH (tparms), - targs); + tparms, targs); } /* Now fix up the type of the template template parm. */ - t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms); + t = fixup_template_type_parm_type (TREE_TYPE (parm), sibling_parms); TREE_TYPE (parm) = t; TREE_VEC_ELT (fixedup_args, idx) = @@ -3898,7 +4289,7 @@ fixup_template_parm (tree parm_desc, 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); + fixup_template_parm_index (index, arglist, sibling_parms); DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index; @@ -3918,39 +4309,99 @@ fixup_template_parm (tree parm_desc, pop_deferring_access_checks (); } -/* Walk the current template parms and properly compute the canonical - types of the dependent types created during - cp_parser_template_parameter_list. */ +/* Walk the innermost template parameters of PARMS parms and properly + compute the canonical types of the dependent types created during + cp_parser_template_parameter_list. ARGLIST contains a TREE_VEC of + arguments built from the elements of PARMS that have been fixed-up + so far. This function udpates ARGLIST as it runs. If the caller + of this function is not interested in getting ARGLIST, it can + set it to NULL_TREE. */ -void -fixup_template_parms (void) +static void +fixup_innermost_template_parms (tree parms, tree arglist) { - tree arglist; tree parameter_vec; - tree fixedup_args; int i, num_parms; - parameter_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms); + if (parms == NULL_TREE || parms == error_mark_node) + return; + + parameter_vec = INNERMOST_TEMPLATE_PARMS (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); + if (arglist == NULL_TREE) + { + tree fixedup_args; + arglist = template_parms_to_args (parms); + /* This vector contains the current innermost template parms + that have been fixed up so far. The form of ARGLIST is + suitable to be passed to tsubst* functions as their ARGS + argument. */ + fixedup_args = make_tree_vec (num_parms); + arglist = add_outermost_template_args (arglist, fixedup_args); + } /* 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); + i, parameter_vec, arglist); +} + +/* Fixup the template parameters PARMS; that is, compute the + canonical types of each parameter therein. + + Note that PARMS must be of the form described in the comments of + the DECL_TEMPLATE_PARMS accessor in cp-tree.h. */ + +void +fixup_template_parms (tree parms) +{ + tree level, args; + int i; + + if (parms == NULL_TREE || parms == error_mark_node) + return; + + + if (TMPL_PARMS_DEPTH (parms) > 1) + { + int parms_depth = TMPL_PARMS_DEPTH (parms); + args = make_tree_vec (parms_depth); + for (i = 0; i < parms_depth; ++i) + { + level = get_template_parms_at_level (parms, i + 1); + if (level == NULL_TREE) + continue; + TREE_VEC_ELT (args, i) = + make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (level))); + } + } + else + args = make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms))); + + /* Template parms ought to be fixed-up from left to right. */ + parms = nreverse (parms); + + for (level = parms; level != NULL_TREE; level = TREE_CHAIN (level)) + fixup_innermost_template_parms (level, args); + + parms = nreverse (parms); +} + +/* Walk the current template parms and properly compute the canonical + types of the dependent types created during + cp_parser_template_parameter_list. */ + +void +fixup_current_template_parms (void) +{ + fixup_innermost_template_parms (current_template_parms, NULL_TREE); } /* end_template_decl is called after a template declaration is seen. */ @@ -4032,6 +4483,60 @@ template_parm_to_arg (tree t) return t; } +/* Transform a template parameter into an argument, suitable to be + passed to tsubst as an element of its ARGS parameter. */ + +static tree +template_parms_to_args (tree parms) +{ + tree header; + tree args = NULL_TREE; + int length = TMPL_PARMS_DEPTH (parms); + int l = length; + + /* If there is only one level of template parameters, we do not + create a TREE_VEC of TREE_VECs. Instead, we return a single + TREE_VEC containing the arguments. */ + if (length > 1) + args = make_tree_vec (length); + + for (header = parms; header; header = TREE_CHAIN (header)) + { + tree a = copy_node (TREE_VALUE (header)); + int i; + + TREE_TYPE (a) = NULL_TREE; + for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) + 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)); +#endif + + if (length > 1) + TREE_VEC_ELT (args, --l) = a; + 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; +} + /* This function returns TRUE if PARM_PACK is a template parameter pack and if ARG_PACK is what template_parm_to_arg returned when passed PARM_PACK. */ @@ -4089,60 +4594,92 @@ arg_from_parm_pack_p (tree arg_pack, tree parm_pack) return false; } -/* 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 - arguments. */ - -static tree -current_template_args (void) -{ - tree header; - tree args = NULL_TREE; - int length = TMPL_PARMS_DEPTH (current_template_parms); - int l = length; +/* When a template parameter PARM_PACK is a pack that is part of a + pack expansion EXPANSION and when EXPANSION has been partially + instantiated (or rather substituted into) with a set of arguments + ARGS0 which depth is less than the level of PARM_PACK, the level of + PARM_PACK is not reduced, unlike what happens for a non-pack + template parameter. + + Rather, EXPANSION remembers ARGS0 and later, when an attempt to + instantiate EXPANSION with a set of arguments ARGS1 which is so + that the set {ARGS0, ARGS1} is deep enough to fully instantiate + EXPANSION, EXPANSION is substituted into with the arguments {ARGS0, + ARGS1}. + + So in the time interval between when EXPANSION remembers ARGS0 and + when it gets ARGS1, the level of E stays the same, even if it has + been morally reduced. If the type fixup of E happens in that time + interval, we'll need to be able to detect that ARG_PACK is the + result of template_parm_to_arg called on PARM_PACK' - which is the result + of morally reducing the level of PARM_PACK and fixing up its + type. + + Note that because of the complication that arises due to the way + pack expansions handle partial instantiations of parameter packs, + arg_from_parm_pack_p won't work on arg_pack and parm_pack. + + This function should thus return true if ARG_PACK is the result of + 1/ morally level-reducing parameter pack PARM_PACK + 2/ fixing-up the result of 1/ + 3/ passing the result 2/ to template_parm_to_arg. + + FIXME: This function does an approximation, as it only checks that + the levels of PARM_PACK/EXPANSION and ARG_PACK do match. For it to + be precise, I think the TEMPLATE_PARM_INDEX of PARM_PACK should + track its pre-fixup type, so that ARG_PACK could be compared with + that type instead. But that would increase the size of the + template_parm_index_s struct, as I don't see where else I could + store the pre-fixup type. */ - /* If there is only one level of template parameters, we do not - create a TREE_VEC of TREE_VECs. Instead, we return a single - TREE_VEC containing the arguments. */ - if (length > 1) - args = make_tree_vec (length); +static bool +arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (tree arg_pack, + tree parm_pack, + tree expansion) +{ + /* We want parm_pack to be a type or non-type parameter pack. */ + if (parm_pack == NULL_TREE + || (!template_type_parameter_type_p (parm_pack) + && !(DECL_P (parm_pack) && DECL_TEMPLATE_PARM_P (parm_pack)) + && TREE_CODE (parm_pack) != TEMPLATE_PARM_INDEX)) + return false; - for (header = current_template_parms; header; header = TREE_CHAIN (header)) + if (arg_pack + && TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1 + && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0))) { - tree a = copy_node (TREE_VALUE (header)); - int i; + tree e = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack), 0); + tree p = PACK_EXPANSION_PATTERN (e); + tree extra_args = PACK_EXPANSION_EXTRA_ARGS (expansion); + tree index_p, index_parm_pack; + int extra_args_depth = extra_args ? TMPL_ARGS_DEPTH (extra_args) : 0; - TREE_TYPE (a) = NULL_TREE; - for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) - TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i)); + if (TREE_CODE (p) != TREE_CODE (parm_pack)) + return false; -#ifdef ENABLE_CHECKING - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a)); -#endif + index_p = get_template_parm_index (p); + index_parm_pack = get_template_parm_index (parm_pack); - if (length > 1) - TREE_VEC_ELT (args, --l) = a; - else - args = a; + if (extra_args_depth != 0 + && (TEMPLATE_PARM_LEVEL (index_p) + == TEMPLATE_PARM_LEVEL (index_parm_pack) - extra_args_depth) + && (TEMPLATE_PARM_IDX (index_p) + == TEMPLATE_PARM_IDX (index_parm_pack))) + return true; } - if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE) - /* This can happen for template parms of a template template - parameter, e.g: + return false; +} - template class TT> struct S; +/* 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 + arguments. */ - 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; +static tree +current_template_args (void) +{ + return template_parms_to_args (current_template_parms); } /* Update the declared TYPE by doing any lookups which were thought to be @@ -4851,6 +5388,8 @@ push_template_decl_real (tree decl, bool is_friend) && TYPE_DECL_ALIAS_P (decl)) /* alias-declaration */ gcc_assert (!DECL_ARTIFICIAL (decl)); + else if (is_friend && TREE_CODE (TREE_TYPE (decl)) == TYPENAME_TYPE) + /* OK */; else { error ("template declaration of %q#D", decl); @@ -4917,7 +5456,8 @@ push_template_decl_real (tree decl, bool is_friend) if (!ctx || TREE_CODE (ctx) == FUNCTION_DECL || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx)) - || (is_friend && !DECL_TEMPLATE_INFO (decl))) + || (is_friend && (!DECL_LANG_SPECIFIC (decl) + || !DECL_TEMPLATE_INFO (decl)))) { if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) @@ -5120,7 +5660,7 @@ template arguments to %qD do not match original template %qD", SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); else { - if (primary && !DECL_LANG_SPECIFIC (decl)) + if ((primary || is_friend) && !DECL_LANG_SPECIFIC (decl)) retrofit_lang_decl (decl); if (DECL_LANG_SPECIFIC (decl)) DECL_TEMPLATE_INFO (decl) = info; @@ -6909,10 +7449,12 @@ coerce_template_parms (tree parms, return new_inner_args; } -/* Returns 1 if template args OT and NT are equivalent. */ +/* Returns 1 if template args OT and NT are equivalent. STRICT + controls how the comparison is done, with the same semantics as + for the last parameter of comptypes. */ static int -template_args_equal (tree ot, tree nt) +template_args_equal_guided (tree ot, tree nt, int strict) { if (nt == ot) return 1; @@ -6921,13 +7463,16 @@ template_args_equal (tree ot, tree nt) if (TREE_CODE (nt) == TREE_VEC) /* For member templates */ - return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt); + return (TREE_CODE (ot) == TREE_VEC + && comp_template_args_guided (ot, nt, NULL, NULL, strict)); else if (PACK_EXPANSION_P (ot)) return (PACK_EXPANSION_P (nt) - && template_args_equal (PACK_EXPANSION_PATTERN (ot), - PACK_EXPANSION_PATTERN (nt)) - && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot), - PACK_EXPANSION_EXTRA_ARGS (nt))); + && template_args_equal_guided (PACK_EXPANSION_PATTERN (ot), + PACK_EXPANSION_PATTERN (nt), + strict) + && template_args_equal_guided (PACK_EXPANSION_EXTRA_ARGS (ot), + PACK_EXPANSION_EXTRA_ARGS (nt), + strict)); else if (ARGUMENT_PACK_P (ot)) { int i, len; @@ -6942,8 +7487,9 @@ template_args_equal (tree ot, tree nt) if (TREE_VEC_LENGTH (npack) != len) return 0; for (i = 0; i < len; ++i) - if (!template_args_equal (TREE_VEC_ELT (opack, i), - TREE_VEC_ELT (npack, i))) + if (!template_args_equal_guided (TREE_VEC_ELT (opack, i), + TREE_VEC_ELT (npack, i), + strict)) return 0; return 1; } @@ -6957,23 +7503,32 @@ template_args_equal (tree ot, tree nt) ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot); if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT) nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt); - return template_args_equal (ot, nt); + return template_args_equal_guided (ot, nt, strict); } else if (TYPE_P (nt)) - return TYPE_P (ot) && same_type_p (ot, nt); + return TYPE_P (ot) && comptypes (ot, nt, strict); else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot)) return 0; else return cp_tree_equal (ot, nt); } +/* Returns 1 if template args OT and NT are equivalent. */ + +static int +template_args_equal (tree ot, tree nt) +{ + return template_args_equal_guided (ot, nt, COMPARE_STRICT); +} + /* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of template arguments. Returns 0 otherwise, and updates OLDARG_PTR and NEWARG_PTR with the offending arguments if they are non-NULL. */ -static int -comp_template_args_with_info (tree oldargs, tree newargs, - tree *oldarg_ptr, tree *newarg_ptr) +int +comp_template_args_guided (tree oldargs, tree newargs, + tree *oldarg_ptr, tree *newarg_ptr, + int strict) { int i; @@ -6991,7 +7546,7 @@ comp_template_args_with_info (tree oldargs, tree newargs, tree nt = TREE_VEC_ELT (newargs, i); tree ot = TREE_VEC_ELT (oldargs, i); - if (! template_args_equal (ot, nt)) + if (! template_args_equal_guided (ot, nt, strict)) { if (oldarg_ptr != NULL) *oldarg_ptr = ot; @@ -7009,7 +7564,8 @@ comp_template_args_with_info (tree oldargs, tree newargs, int comp_template_args (tree oldargs, tree newargs) { - return comp_template_args_with_info (oldargs, newargs, NULL, NULL); + return comp_template_args_guided (oldargs, newargs, + NULL, NULL, COMPARE_STRICT); } static void @@ -8854,6 +9410,18 @@ instantiate_class_template_1 (tree type) member; member = TREE_CHAIN (member)) { tree t = TREE_VALUE (member); + tree tinfo = get_template_info (t); + + if (tinfo && TREE_CODE (TI_TEMPLATE (tinfo)) == TEMPLATE_DECL) + { + ++processing_template_decl; + /* prepare possible partial instantiation of member + template by fixing-up template parms which level are + going to be reduced by the partial instantiation. */ + tsubst_template_parms (DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo)), + args, tf_none); + --processing_template_decl; + } if (TREE_PURPOSE (member)) { @@ -9362,7 +9930,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, return result; } - if (arg_from_parm_pack_p (arg_pack, parm_pack)) + if (arg_from_parm_pack_p (arg_pack, parm_pack) + || arg_from_reduced_and_fixedup_parm_pack_of_expansion_p (arg_pack, + parm_pack, + t)) /* The argument pack that the parameter maps to is just an expansion of the parameter itself, such as one would find in the implicit typedef of a class inside the class itself. @@ -9716,7 +10287,14 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) PARMS, then the result will contain n levels of PARMS. For example, if PARMS is `template template template ' and ARGS is {{int}, {double}} then the - result will be `template '. */ + result will be `template '. + + If the depth of ARGS is less than the depth of PARMS, it most + probably means we are looking at the partial instantiation of a + member template. This implies that the resulting set of template + parms is going to be level-reduced. In that case, this function + does the proper type fixing-up of the reduced template + parameters. */ static tree tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) @@ -9724,6 +10302,9 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) tree r = NULL_TREE; tree* new_parms; + if (parms == NULL_TREE || parms == error_mark_node) + return parms; + /* When substituting into a template, we must set PROCESSING_TEMPLATE_DECL as the template parameters may be dependent if they are based on one-another, and the dependency @@ -9761,6 +10342,7 @@ tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain) new_vec, NULL_TREE); } + fixup_template_parms (r); --processing_template_decl; return r; @@ -9829,6 +10411,12 @@ tsubst_aggr_type (tree t, int saved_unevaluated_operand; int saved_inhibit_evaluation_warnings; + /* If T is a member template being partially instantiated, + fixup its template parameters that are to be + level-reduced. */ + tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (t)), + args, complain); + /* In "sizeof(X)" we need to evaluate "I". */ saved_unevaluated_operand = cp_unevaluated_operand; cp_unevaluated_operand = 0; @@ -9998,6 +10586,15 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) tree spec; tree tmpl_args; tree full_args; + tree fixedup_parms; + + /* If T is a member template being partially instantiated, + fixup its template parameters that are to be + level-reduced. */ + ++processing_template_decl; + fixedup_parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), + args, complain); + --processing_template_decl; if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)) { @@ -10073,6 +10670,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) TREE_TYPE (r) = new_type; CLASSTYPE_TI_TEMPLATE (new_type) = r; + DECL_TEMPLATE_PARMS (r) = fixedup_parms; DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type); DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type); DECL_CONTEXT (r) = TYPE_CONTEXT (new_type); @@ -10088,6 +10686,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_TEMPLATE_RESULT (r) = new_decl; DECL_TI_TEMPLATE (new_decl) = r; + DECL_TEMPLATE_PARMS (r) = fixedup_parms; TREE_TYPE (r) = TREE_TYPE (new_decl); DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl); DECL_CONTEXT (r) = DECL_CONTEXT (new_decl); @@ -10097,13 +10696,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE; DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE; - /* The template parameters for this new template are all the - template parameters for the old template, except the - outermost level of parameters. */ - DECL_TEMPLATE_PARMS (r) - = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args, - complain); - if (PRIMARY_TEMPLATE_P (t)) DECL_PRIMARY_TEMPLATE (r) = r; @@ -11711,16 +12303,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) case UNBOUND_CLASS_TEMPLATE: { + /* If T is a member template being partially instantiated, + fixup its template parmeters that are to be level-reduced, + upfront. */ + tree parm_list = + tsubst_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t)), + args, complain); tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain, in_decl, /*entering_scope=*/1); tree name = TYPE_IDENTIFIER (t); - tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t)); if (ctx == error_mark_node || name == error_mark_node) return error_mark_node; - if (parm_list) - parm_list = tsubst_template_parms (parm_list, args, complain); return make_unbound_class_template (ctx, name, parm_list, complain); } @@ -16077,8 +16672,9 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms, tree bad_old_arg = NULL_TREE, bad_new_arg = NULL_TREE; tree old_args = ARGUMENT_PACK_ARGS (old_pack); - if (!comp_template_args_with_info (old_args, new_args, - &bad_old_arg, &bad_new_arg)) + if (!comp_template_args_guided (old_args, new_args, + &bad_old_arg, &bad_new_arg, + COMPARE_STRICT)) /* Inconsistent unification of this parameter pack. */ return unify_parameter_pack_inconsistent (explain_p, bad_old_arg, @@ -19066,15 +19662,13 @@ get_mostly_instantiated_function_type (tree decl) int i; tree partial_args; - /* Replace the innermost level of the TARGS with NULL_TREEs to - let tsubst know not to substitute for those parameters. */ - partial_args = make_tree_vec (TREE_VEC_LENGTH (targs)); + /* Copy all but the innermost level of the TARGS to let tsubst + below know not to substitute for those parameters and + properly perform the partial substituting of fn_type. */ + partial_args = make_tree_vec (TREE_VEC_LENGTH (targs) - 1); for (i = 1; i < TMPL_ARGS_DEPTH (targs); ++i) SET_TMPL_ARGS_LEVEL (partial_args, i, TMPL_ARGS_LEVEL (targs, i)); - SET_TMPL_ARGS_LEVEL (partial_args, - TMPL_ARGS_DEPTH (targs), - make_tree_vec (DECL_NTPARMS (tmpl))); /* Make sure that we can see identifiers, and compute access correctly. */ @@ -19090,7 +19684,6 @@ get_mostly_instantiated_function_type (tree decl) innermost set of parameters. This step is important if the innermost set of template parameters contains value parameters whose types depend on outer template parameters. */ - TREE_VEC_LENGTH (partial_args)--; tparms = tsubst_template_parms (tparms, partial_args, tf_error); pop_access_scope (decl); @@ -20214,7 +20807,7 @@ make_auto (void) TYPE_DECL, get_identifier ("auto"), au); 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, + (0, processing_template_decl + 1, NULL_TREE, 0, TYPE_NAME (au), NULL_TREE); TYPE_CANONICAL (au) = canonical_type_parameter (au); DECL_ARTIFICIAL (TYPE_NAME (au)) = 1; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index b80b52a..04bdedd 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2178,7 +2178,7 @@ decl_anon_ns_mem_p (const_tree decl) CALL_EXPRS. Return whether they are equivalent. */ static bool -called_fns_equal (tree t1, tree t2) +called_fns_equal (tree t1, tree t2, int strict) { /* Core 1321: dependent names are equivalent even if the overload sets are different. But do compare explicit template arguments. */ @@ -2195,17 +2195,21 @@ called_fns_equal (tree t1, tree t2) targs1 = TREE_OPERAND (t1, 1); if (TREE_CODE (t2) == TEMPLATE_ID_EXPR) targs2 = TREE_OPERAND (t2, 1); - return cp_tree_equal (targs1, targs2); + return compare_trees (targs1, targs2, strict); } else return cp_tree_equal (t1, t2); } /* Return truthvalue of whether T1 is the same tree structure as T2. - Return 1 if they are the same. Return 0 if they are different. */ + STRICT controls how the comparison is done, with the same semantics + as the for the last parameter of comptypes. Please make sure that + any type or tree comparison function used in this function is a + variant that takes this STRICT parameter. Return 1 if they are the + same. Return 0 if they are different. */ bool -cp_tree_equal (tree t1, tree t2) +compare_trees (tree t1, tree t2, int strict) { enum tree_code code1, code2; @@ -2251,14 +2255,14 @@ cp_tree_equal (tree t1, tree t2) TREE_FIXED_CST (t2)); case COMPLEX_CST: - return cp_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2)) - && cp_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); + return compare_trees (TREE_REALPART (t1), TREE_REALPART (t2), strict) + && compare_trees (TREE_IMAGPART (t1), TREE_IMAGPART (t2), strict); case CONSTRUCTOR: /* We need to do this when determining whether or not two non-type pointer to member function template arguments are the same. */ - if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)) + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict) || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2)) return false; { @@ -2267,35 +2271,35 @@ cp_tree_equal (tree t1, tree t2) FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value) { constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i); - if (!cp_tree_equal (field, elt2->index) - || !cp_tree_equal (value, elt2->value)) + if (!compare_trees (field, elt2->index, strict) + || !compare_trees (value, elt2->value, strict)) return false; } } return true; case TREE_LIST: - if (!cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) + if (!compare_trees (TREE_PURPOSE (t1), TREE_PURPOSE (t2), strict)) return false; - if (!cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + if (!compare_trees (TREE_VALUE (t1), TREE_VALUE (t2), strict)) return false; - return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); + return compare_trees (TREE_CHAIN (t1), TREE_CHAIN (t2), strict); case SAVE_EXPR: - return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict); case CALL_EXPR: { tree arg1, arg2; call_expr_arg_iterator iter1, iter2; - if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2))) + if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2), strict)) return false; for (arg1 = first_call_expr_arg (t1, &iter1), arg2 = first_call_expr_arg (t2, &iter2); arg1 && arg2; arg1 = next_call_expr_arg (&iter1), arg2 = next_call_expr_arg (&iter2)) - if (!cp_tree_equal (arg1, arg2)) + if (!compare_trees (arg1, arg2, strict)) return false; if (arg1 || arg2) return false; @@ -2317,28 +2321,30 @@ cp_tree_equal (tree t1, tree t2) else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE && !DECL_RTL_SET_P (o2)) /*Nop*/; - else if (!cp_tree_equal (o1, o2)) + else if (!compare_trees (o1, o2, strict)) return false; - return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); + return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1), + strict); } case WITH_CLEANUP_EXPR: - if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))) + if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), strict)) return false; - return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1)); + return compare_trees (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1), strict); case COMPONENT_REF: if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) return false; - return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); + return compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), + strict); case PARM_DECL: /* For comparing uses of parameters in late-specified return types with an out-of-class definition of the function, but can also come up for expressions that involve 'this' in a member function template. */ - if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + if (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) { if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2)) return false; @@ -2361,19 +2367,18 @@ cp_tree_equal (tree t1, tree t2) return (BASELINK_BINFO (t1) == BASELINK_BINFO (t2) && BASELINK_ACCESS_BINFO (t1) == BASELINK_ACCESS_BINFO (t2) && BASELINK_QUALIFIED_P (t1) == BASELINK_QUALIFIED_P (t2) - && cp_tree_equal (BASELINK_FUNCTIONS (t1), - BASELINK_FUNCTIONS (t2))); + && compare_trees (BASELINK_FUNCTIONS (t1), + BASELINK_FUNCTIONS (t2), strict)); case TEMPLATE_PARM_INDEX: - if (TEMPLATE_PARM_NUM_SIBLINGS (t1) - != TEMPLATE_PARM_NUM_SIBLINGS (t2)) + if (!(TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2) + && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2) + && (TEMPLATE_PARM_PARAMETER_PACK (t1) + == TEMPLATE_PARM_PARAMETER_PACK (t2)) + && comptypes (TREE_TYPE (TEMPLATE_PARM_DECL (t1)), + TREE_TYPE (TEMPLATE_PARM_DECL (t2)), strict))) return false; - return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2) - && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2) - && (TEMPLATE_PARM_PARAMETER_PACK (t1) - == TEMPLATE_PARM_PARAMETER_PACK (t2)) - && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)), - TREE_TYPE (TEMPLATE_PARM_DECL (t2)))); + return comp_template_parms_siblings (t1, t2, strict); case TEMPLATE_ID_EXPR: return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)) @@ -2385,8 +2390,9 @@ cp_tree_equal (tree t1, tree t2) if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2)) return false; for (ix = TREE_VEC_LENGTH (t1); ix--;) - if (!cp_tree_equal (TREE_VEC_ELT (t1, ix), - TREE_VEC_ELT (t2, ix))) + if (!compare_trees (TREE_VEC_ELT (t1, ix), + TREE_VEC_ELT (t2, ix), + strict)) return false; return true; } @@ -2400,16 +2406,17 @@ cp_tree_equal (tree t1, tree t2) if (TREE_CODE (o1) != TREE_CODE (o2)) return false; if (TYPE_P (o1)) - return same_type_p (o1, o2); + return comptypes (o1, o2, strict); else - return cp_tree_equal (o1, o2); + return compare_trees (o1, o2, strict); } case MODOP_EXPR: { tree t1_op1, t2_op1; - if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))) + if (!compare_trees (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), + strict)) return false; t1_op1 = TREE_OPERAND (t1, 1); @@ -2417,7 +2424,7 @@ cp_tree_equal (tree t1, tree t2) if (TREE_CODE (t1_op1) != TREE_CODE (t2_op1)) return false; - return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2)); + return compare_trees (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2), strict); } case PTRMEM_CST: @@ -2426,18 +2433,18 @@ cp_tree_equal (tree t1, tree t2) if (PTRMEM_CST_MEMBER (t1) != PTRMEM_CST_MEMBER (t2)) return false; - return same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2)); + return comptypes (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2), strict); case OVERLOAD: if (OVL_FUNCTION (t1) != OVL_FUNCTION (t2)) return false; - return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2)); + return compare_trees (OVL_CHAIN (t1), OVL_CHAIN (t2), strict); case TRAIT_EXPR: if (TRAIT_EXPR_KIND (t1) != TRAIT_EXPR_KIND (t2)) return false; - return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2)) - && same_type_p (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2)); + return comptypes (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2), strict) + && comptypes (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2), strict); case CAST_EXPR: case STATIC_CAST_EXPR: @@ -2446,16 +2453,18 @@ cp_tree_equal (tree t1, tree t2) case DYNAMIC_CAST_EXPR: case IMPLICIT_CONV_EXPR: case NEW_EXPR: - if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) return false; /* Now compare operands as usual. */ break; case DEFERRED_NOEXCEPT: - return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1), - DEFERRED_NOEXCEPT_PATTERN (t2)) - && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1), - DEFERRED_NOEXCEPT_ARGS (t2))); + return (compare_trees (DEFERRED_NOEXCEPT_PATTERN (t1), + DEFERRED_NOEXCEPT_PATTERN (t2), + strict) + && comp_template_args_guided (DEFERRED_NOEXCEPT_ARGS (t1), + DEFERRED_NOEXCEPT_ARGS (t2), + NULL, NULL, strict)); break; default: @@ -2480,14 +2489,15 @@ cp_tree_equal (tree t1, tree t2) return false; for (i = 0; i < n; ++i) - if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) + if (!compare_trees (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i), + strict)) return false; return true; } case tcc_type: - return same_type_p (t1, t2); + return comptypes (t1, t2, strict); default: gcc_unreachable (); } @@ -2495,6 +2505,15 @@ cp_tree_equal (tree t1, tree t2) return false; } +/* Return truthvalue of whether T1 is the same tree structure as T2. + Return 1 if they are the same. Return 0 if they are different. */ + +bool +cp_tree_equal (tree t1, tree t2) +{ + return compare_trees (t1, t2, COMPARE_STRICT); +} + /* The type of ARG when used as an lvalue. */ tree diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ba5ae46..cff910b 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -53,6 +53,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree, static int comp_ptr_ttypes_real (tree, tree, int); static bool comp_except_types (tree, tree, bool); static bool comp_array_types (const_tree, const_tree, bool); +static bool compparms_guided (const_tree, const_tree, int); static tree pointer_diff (tree, tree, tree); static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t); static void casts_away_constness_r (tree *, tree *); @@ -1119,13 +1120,56 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration) return true; } +/* Return true iff the two instances of TEMPLATE_PARM_INDEX are + equivalent. STRICT controls how the comparison is done, with the + same semantics as the last parameter of comptypes. */ + +bool +comp_template_parms_siblings (tree index1, + tree index2, + int strict) +{ + tree siblings1, siblings2; + + gcc_assert (index1 != NULL_TREE + && index2 != NULL_TREE + && TREE_CODE (index1) == TREE_CODE (index2) + && TREE_CODE (index1) == TEMPLATE_PARM_INDEX); + + if (strict & COMPARE_NO_SIBLINGS) + return true; + + siblings1 = TEMPLATE_PARM_SIBLINGS (index1); + siblings2 = TEMPLATE_PARM_SIBLINGS (index2); + + if (siblings1 == siblings2) + return true; + + /* If T1 and T2 belong to different template parm lists let's assume + they are different. */ + + if ((siblings1 != NULL_TREE) != (siblings2 != NULL_TREE)) + return false; + + if (TREE_VEC_LENGTH (siblings1) != TREE_VEC_LENGTH (siblings2)) + return false; + + if (!comp_template_parm_levels (siblings1, siblings2, + strict | COMPARE_NO_SIBLINGS)) + return false; + + return true; +} + /* Compare the relative position of T1 and T2 into their respective template parameter list. - T1 and T2 must be template parameter types. + T1 and T2 must be template parameter types. STRICT controls how + the comparison is done, with the same semantics as the for the last + parameter of comptypes. Return TRUE if T1 and T2 have the same position, FALSE otherwise. */ static bool -comp_template_parms_position (tree t1, tree t2) +comp_template_parms_position (tree t1, tree t2, int strict) { tree index1, index2; gcc_assert (t1 && t2 @@ -1137,19 +1181,16 @@ comp_template_parms_position (tree t1, tree t2) index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1)); index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2)); - /* 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; - - /* Then compare their relative position. */ + /* 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; + if (!comp_template_parms_siblings (index1, index2, strict)) + return false; + return true; } @@ -1233,11 +1274,12 @@ structural_comptypes (tree t1, tree t2, int strict) case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: - if (!comp_template_parms_position (t1, t2)) + if (!comp_template_parms_position (t1, t2, strict)) return false; - if (!comp_template_parms + if (!comp_template_parms_guided (DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)), - DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)))) + DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2)), + strict)) return false; if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM) break; @@ -1250,7 +1292,9 @@ structural_comptypes (tree t1, tree t2, int strict) if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2) && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2) || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM) - && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2))) + && comp_template_args_guided (TYPE_TI_ARGS (t1), + TYPE_TI_ARGS (t2), + NULL, NULL, strict)) break; if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2)) @@ -1264,7 +1308,7 @@ structural_comptypes (tree t1, tree t2, int strict) if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2), strict & ~COMPARE_REDECLARATION)) return false; - if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) return false; break; @@ -1276,15 +1320,17 @@ structural_comptypes (tree t1, tree t2, int strict) case POINTER_TYPE: if (TYPE_MODE (t1) != TYPE_MODE (t2) || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2) - || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2), + strict & ~COMPARE_REDECLARATION)) return false; break; case METHOD_TYPE: case FUNCTION_TYPE: - if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) return false; - if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))) + if (!compparms_guided (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2), + strict)) return false; break; @@ -1297,43 +1343,48 @@ structural_comptypes (tree t1, tree t2, int strict) case 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)) + if (!comp_template_parms_position (t1, t2, strict)) return false; break; case TYPENAME_TYPE: - if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1), - TYPENAME_TYPE_FULLNAME (t2))) + if (!compare_trees (TYPENAME_TYPE_FULLNAME (t1), + TYPENAME_TYPE_FULLNAME (t2), + strict)) return false; /* Qualifiers don't matter on scopes. */ - if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1), - TYPE_CONTEXT (t2))) + if (!same_type_ignoring_top_level_qualifiers_guided_p (TYPE_CONTEXT (t1), + TYPE_CONTEXT (t2), + strict)) return false; break; case UNBOUND_CLASS_TEMPLATE: - if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2))) + if (!compare_trees (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2), + strict)) return false; - if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2))) + if (!comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), strict)) return false; break; case COMPLEX_TYPE: - if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + if (!comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) return false; break; case VECTOR_TYPE: if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2) - || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))) + || !comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)) return false; break; case TYPE_PACK_EXPANSION: - return (same_type_p (PACK_EXPANSION_PATTERN (t1), - PACK_EXPANSION_PATTERN (t2)) - && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1), - PACK_EXPANSION_EXTRA_ARGS (t2))); + return (comptypes (PACK_EXPANSION_PATTERN (t1), + PACK_EXPANSION_PATTERN (t2), + strict) + && comp_template_args_guided (PACK_EXPANSION_EXTRA_ARGS (t1), + PACK_EXPANSION_EXTRA_ARGS (t2), + NULL, NULL, strict)); case DECLTYPE_TYPE: if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1) @@ -1342,14 +1393,16 @@ structural_comptypes (tree t1, tree t2, int strict) != DECLTYPE_FOR_LAMBDA_CAPTURE (t2)) || (DECLTYPE_FOR_LAMBDA_PROXY (t1) != DECLTYPE_FOR_LAMBDA_PROXY (t2)) - || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1), - DECLTYPE_TYPE_EXPR (t2))) + || !compare_trees (DECLTYPE_TYPE_EXPR (t1), + DECLTYPE_TYPE_EXPR (t2), + strict)) return false; break; case UNDERLYING_TYPE: - return same_type_p (UNDERLYING_TYPE_TYPE (t1), - UNDERLYING_TYPE_TYPE (t2)); + return comptypes (UNDERLYING_TYPE_TYPE (t1), + UNDERLYING_TYPE_TYPE (t2), + strict); default: return false; @@ -1416,15 +1469,31 @@ comptypes (tree t1, tree t2, int strict) } /* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring - top-level qualifiers. */ + top-level qualifiers. STRICT controls how the type comparison is + done, with the same semantics as for the last parameter of + comptypes. */ bool -same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2) +same_type_ignoring_top_level_qualifiers_guided_p (tree type1, + tree type2, + int strict) { if (type1 == error_mark_node || type2 == error_mark_node) return false; - return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2)); + return comptypes (TYPE_MAIN_VARIANT (type1), + TYPE_MAIN_VARIANT (type2), + strict); +} + +/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring + top-level qualifiers. */ + +bool +same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2) +{ + return same_type_ignoring_top_level_qualifiers_guided_p (type1, type2, + COMPARE_STRICT); } /* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ @@ -1479,10 +1548,10 @@ comp_cv_qual_signature (tree type1, tree type2) /* Return true if two parameter type lists PARMS1 and PARMS2 are equivalent in the sense that functions with those parameter types can have equivalent types. The two lists must be equivalent, - element by element. */ + element by element. STRICT controls how the comparison is done. */ -bool -compparms (const_tree parms1, const_tree parms2) +static bool +compparms_guided (const_tree parms1, const_tree parms2, int strict) { const_tree t1, t2; @@ -1497,12 +1566,23 @@ compparms (const_tree parms1, const_tree parms2) they fail to match. */ if (!t1 || !t2) return false; - if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2))) + if (!comptypes (TREE_VALUE (t1), TREE_VALUE (t2), strict)) return false; } return true; } +/* Return true if two parameter type lists PARMS1 and PARMS2 are + equivalent in the sense that functions with those parameter types + can have equivalent types. The two lists must be equivalent, + element by element. */ + +bool +compparms (const_tree parms1, const_tree parms2) +{ + return compparms_guided (parms1, parms2, COMPARE_STRICT); +} + /* Process a sizeof or alignof expression where the operand is a type. */ diff --git a/gcc/testsuite/g++.dg/template/crash84.C b/gcc/testsuite/g++.dg/template/crash84.C index c42f85c..69ee87c 100644 --- a/gcc/testsuite/g++.dg/template/crash84.C +++ b/gcc/testsuite/g++.dg/template/crash84.C @@ -4,8 +4,8 @@ template struct a { - template