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.
This commit is contained in:
parent
875342766d
commit
fc50d9a252
72
gcc/cp/pt.cc
72
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 <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;
|
||||
|
20
gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C
Normal file
20
gcc/testsuite/g++.dg/cpp0x/variadic-alias6.C
Normal file
@ -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" }
|
16
gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C
Normal file
16
gcc/testsuite/g++.dg/cpp0x/variadic-alias7.C
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user