From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id 471593858C56; Mon, 28 Mar 2022 15:04:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 471593858C56 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jason Merrill To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-7857] c++: hash table ICE with variadic alias [PR105003] X-Act-Checkin: gcc X-Git-Author: Jason Merrill X-Git-Refname: refs/heads/master X-Git-Oldrev: 875342766d42988fa2f8eb7d34ef562ba69e340a X-Git-Newrev: fc50d9a252c89c1bac78192bd0884ff23f2bf48b Message-Id: <20220328150412.471593858C56@sourceware.org> Date: Mon, 28 Mar 2022 15:04:12 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Mar 2022 15:04:12 -0000 https://gcc.gnu.org/g:fc50d9a252c89c1bac78192bd0884ff23f2bf48b commit r12-7857-gfc50d9a252c89c1bac78192bd0884ff23f2bf48b Author: Jason Merrill Date: Fri Mar 25 13:13:35 2022 -0400 c++: hash table ICE with variadic alias [PR105003] For PR104008 we thought it might be enough to keep strip_typedefs from removing this alias template specialization, but this PR demonstrates that other parts of the compiler also need to know to consider it dependent. So, this patch changes complex_alias_template_p to no longer consider template parameters used when their only use appears in a pack expansion, unless they are the parameter packs being expanded. To do that I also needed to change it to use cp_walk_tree instead of for_each_template_parm. It occurs to me that find_template_parameters should probably also use cp_walk_tree, but I'm not messing with that now. PR c++/105003 PR c++/104008 PR c++/102869 gcc/cp/ChangeLog: * pt.cc (complex_alias_template_r): walk_tree callback, replacing uses_all_template_parms_r, complex_pack_expansion_r. (complex_alias_template_p): Adjust. * tree.cc (strip_typedefs): Revert r12-7710 change. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/variadic-alias6.C: New test. * g++.dg/cpp0x/variadic-alias7.C: New test. Diff: --- gcc/cp/pt.cc | 72 ++++++++++++++++++---------- gcc/cp/tree.cc | 13 +---- gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C | 20 ++++++++ gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C | 16 +++++++ 4 files changed, 85 insertions(+), 36 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 678063f6e4c..3df509bbed0 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6460,10 +6460,7 @@ alias_template_specialization_p (const_tree t, return NULL_TREE; } -/* An alias template is complex from a SFINAE perspective if a template-id - using that alias can be ill-formed when the expansion is not, as with - the void_t template. We determine this by checking whether the - expansion for the alias template uses all its template parameters. */ +/* Data structure for complex_alias_template_*. */ struct uses_all_template_parms_data { @@ -6471,31 +6468,36 @@ struct uses_all_template_parms_data bool *seen; }; -static int -uses_all_template_parms_r (tree t, void *data_) +/* walk_tree callback for complex_alias_template_p. */ + +static tree +complex_alias_template_r (tree *tp, int *walk_subtrees, void *data_) { - struct uses_all_template_parms_data &data - = *(struct uses_all_template_parms_data*)data_; - tree idx = get_template_parm_index (t); + tree t = *tp; + auto &data = *(struct uses_all_template_parms_data*)data_; - if (TEMPLATE_PARM_LEVEL (idx) == data.level) - data.seen[TEMPLATE_PARM_IDX (idx)] = true; - return 0; -} + switch (TREE_CODE (t)) + { + case TEMPLATE_TYPE_PARM: + case TEMPLATE_PARM_INDEX: + case TEMPLATE_TEMPLATE_PARM: + case BOUND_TEMPLATE_TEMPLATE_PARM: + { + tree idx = get_template_parm_index (t); + if (TEMPLATE_PARM_LEVEL (idx) == data.level) + data.seen[TEMPLATE_PARM_IDX (idx)] = true; + } -/* for_each_template_parm any_fn callback for complex_alias_template_p. */ + default:; + } + + if (!PACK_EXPANSION_P (t)) + return 0; -static int -complex_pack_expansion_r (tree t, void *data_) -{ /* An alias template with a pack expansion that expands a pack from the enclosing class needs to be considered complex, to avoid confusion with the same pack being used as an argument to the alias's own template parameter (91966). */ - if (!PACK_EXPANSION_P (t)) - return 0; - struct uses_all_template_parms_data &data - = *(struct uses_all_template_parms_data*)data_; for (tree pack = PACK_EXPANSION_PARAMETER_PACKS (t); pack; pack = TREE_CHAIN (pack)) { @@ -6505,11 +6507,34 @@ complex_pack_expansion_r (tree t, void *data_) int idx, level; template_parm_level_and_index (parm_pack, &level, &idx); if (level < data.level) - return 1; + return t; + + /* Consider the expanded packs to be used outside the expansion... */ + data.seen[idx] = true; } + + /* ...but don't walk into the pattern. Consider PR104008: + + template + using IsOneOf = disjunction...>; + + where IsOneOf seemingly uses all of its template parameters in its + expansion (and does not expand a pack from the enclosing class), so the + alias was not marked as complex. However, if it is used like + "IsOneOf", the empty pack for Ts means that T no longer appears in the + expansion. So only Ts is considered used by the pack expansion. */ + *walk_subtrees = false; + return 0; } +/* An alias template is complex from a SFINAE perspective if a template-id + using that alias can be ill-formed when the expansion is not, as with + the void_t template. + + Returns 1 if always complex, 0 if not complex, -1 if complex iff any of the + template arguments are empty packs. */ + static bool complex_alias_template_p (const_tree tmpl) { @@ -6530,8 +6555,7 @@ complex_alias_template_p (const_tree tmpl) for (int i = 0; i < len; ++i) data.seen[i] = false; - if (for_each_template_parm (pat, uses_all_template_parms_r, &data, - NULL, true, complex_pack_expansion_r)) + if (cp_walk_tree_without_duplicates (&pat, complex_alias_template_r, &data)) return true; for (int i = 0; i < len; ++i) if (!data.seen[i]) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 492921721f2..780a8d89165 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -1778,18 +1778,7 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) if (TYPE_P (pat)) { type = strip_typedefs (pat, remove_attributes, flags); - /* Empty packs can thwart our efforts here. Consider - - template - using IsOneOf = disjunction...>; - - where IsOneOf seemingly uses all of its template parameters in - its expansion (and does not expand a pack from the enclosing - class), so the alias is not marked as complex. However, it may - be used as in "IsOneOf", where Ts is an empty parameter pack, - and stripping it down into "disjunction<>" here would exclude the - Ts pack, resulting in an error. */ - if (type != pat && uses_parameter_packs (type)) + if (type != pat) { result = build_distinct_type_copy (t); PACK_EXPANSION_PATTERN (result) = type; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C b/gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C new file mode 100644 index 00000000000..c095bc537d7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C @@ -0,0 +1,20 @@ +// PR c++/105003 +// { dg-do compile { target c++11 } } + +template struct A; +template struct B { }; +template struct C { }; + +// Fn is not complex, since T is used outside the pack expansion, so the two +// partial specializations are equivalent. +template using Fn = T(Ts...); +template struct A*> { }; +template struct A { }; // { dg-error "redefinition" } + +// CB is complex, since T is only used in the pack expansion, so the two +// partial specializations are functionally equivalent but not equivalent. +template using CB = C...>; +template struct A*> { }; +template struct A...>*> { }; // IFNDR +A>*> a; // { dg-error "ambiguous" } +// { dg-prune-output "incomplete" } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C b/gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C new file mode 100644 index 00000000000..41a432a8e41 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C @@ -0,0 +1,16 @@ +// PR c++/102869 +// { dg-do compile { target c++11 } } + +template struct integer_sequence; + +template +using make_index_sequence = integer_sequence<__integer_pack(_Num)...>; + +template struct Tuple; + +template using tuple_t = Tuple...>; + +template +void f() { + tuple_t t; +}