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; +}