@@ -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 <typename T, typename... Ts>
+ using IsOneOf = disjunction<is_same<T, Ts>...>;
+
+ 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<T>", 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])
@@ -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 <typename T, typename... Ts>
- using IsOneOf = disjunction<is_same<T, Ts>...>;
-
- 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<Ts>", 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;
new file mode 100644
@@ -0,0 +1,20 @@
+// PR c++/105003
+// { dg-do compile { target c++11 } }
+
+template <class T> struct A;
+template <class T, class U> struct B { };
+template <class... Ts> struct C { };
+
+// Fn is not complex, since T is used outside the pack expansion, so the two
+// partial specializations are equivalent.
+template <class T, class... Ts> using Fn = T(Ts...);
+template <class T, class... Ts> struct A<Fn<T,Ts...>*> { };
+template <class T, class... Ts> struct A<T(*)(Ts...)> { }; // { 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 <class T, class ...Ts> using CB = C<B<T,Ts>...>;
+template <class T, class ...Ts> struct A<CB<T,Ts...>*> { };
+template <class T, class ...Ts> struct A<C<B<T,Ts>...>*> { }; // IFNDR
+A<C<B<int,int>>*> a; // { dg-error "ambiguous" }
+// { dg-prune-output "incomplete" }
new file mode 100644
@@ -0,0 +1,16 @@
+// PR c++/102869
+// { dg-do compile { target c++11 } }
+
+template<int...> struct integer_sequence;
+
+template<int _Num>
+using make_index_sequence = integer_sequence<__integer_pack(_Num)...>;
+
+template<class...> struct Tuple;
+
+template<int... Is> using tuple_t = Tuple<make_index_sequence<Is>...>;
+
+template<int... Is>
+void f() {
+ tuple_t<Is...> t;
+}