c++: alias in qualified-id in template arg [PR98570]
template_args_equal has handled dependent alias specializations for a while, but in this testcase the actual template argument is a SCOPE_REF, so we called cp_tree_equal, which doesn't handle aliases specially when we get to them. This patch generalizes this by setting a flag so structural_comptypes will check for template alias equivalence (if we aren't doing partial ordering). The existing flag, comparing_specializations, was too broad; in particular, when we're doing decls_match, we want to treat corresponding parameters as equivalent, so we need to separate that from alias comparison. So I introduce the comparing_dependent_aliases flag. From looking at other uses of comparing_specializations, it seems to me that the new flag is what modules wants, as well. The other use of comparing_specializations in structural_comptypes is a hack to deal with spec_hasher::equal not calling push_to_top_level, which we also don't want to tie to the alias comparison semantics. This patch also changes how we get to structural comparison of aliases from checking TYPE_CANONICAL in comptypes to marking the aliases as getting structural comparison when they are built, which is more consistent with how e.g. typename is handled. As I mention in the comment for comparing_dependent_aliases, I think the default should be to treat different dependent aliases for the same type as distinct, only treating them as equal during deduction (particularly partial ordering). But that's a matter for the C++ committee, to try in stage 1. gcc/cp/ChangeLog: PR c++/98570 * cp-tree.h: Declare it. * pt.c (comparing_dependent_aliases): New flag. (template_args_equal, spec_hasher::equal): Set it. (dependent_alias_template_spec_p): Assert that we don't get non-types other than error_mark_node. (instantiate_alias_template): SET_TYPE_STRUCTURAL_EQUALITY on complex alias specializations. Set TYPE_DEPENDENT_P here. (tsubst_decl): Not here. * module.cc (module_state::read_cluster): Set comparing_dependent_aliases instead of comparing_specializations. * tree.c (cp_tree_equal): Remove comparing_specializations module handling. * typeck.c (structural_comptypes): Adjust. (comptypes): Remove comparing_specializations handling. gcc/testsuite/ChangeLog: PR c++/98570 * g++.dg/cpp0x/alias-decl-targ1.C: New test.
This commit is contained in:
parent
bec5dbae56
commit
6e0a231a4a
@ -5449,11 +5449,14 @@ extern GTY(()) tree integer_two_node;
|
||||
function, two inside the body of a function in a local class, etc.) */
|
||||
extern int function_depth;
|
||||
|
||||
/* Nonzero if we are inside eq_specializations, which affects
|
||||
comparison of PARM_DECLs in cp_tree_equal and alias specializations
|
||||
in structrual_comptypes. */
|
||||
/* Nonzero if we are inside spec_hasher::equal, which affects
|
||||
comparison of PARM_DECLs in cp_tree_equal. */
|
||||
extern int comparing_specializations;
|
||||
|
||||
/* Nonzero if we want different dependent aliases to compare as unequal.
|
||||
FIXME we should always do this except during deduction/ordering. */
|
||||
extern int comparing_dependent_aliases;
|
||||
|
||||
/* When comparing specializations permit context _FROM to match _TO. */
|
||||
extern tree map_context_from;
|
||||
extern tree map_context_to;
|
||||
|
@ -14801,7 +14801,7 @@ module_state::read_cluster (unsigned snum)
|
||||
dump.indent ();
|
||||
|
||||
/* We care about structural equality. */
|
||||
comparing_specializations++;
|
||||
comparing_dependent_aliases++;
|
||||
|
||||
/* First seed the imports. */
|
||||
while (tree import = sec.tree_node ())
|
||||
@ -14976,7 +14976,7 @@ module_state::read_cluster (unsigned snum)
|
||||
#undef cfun
|
||||
cfun = old_cfun;
|
||||
current_function_decl = old_cfd;
|
||||
comparing_specializations--;
|
||||
comparing_dependent_aliases--;
|
||||
|
||||
dump.outdent ();
|
||||
dump () && dump ("Read section:%u", snum);
|
||||
|
52
gcc/cp/pt.c
52
gcc/cp/pt.c
@ -1709,6 +1709,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
|
||||
|
||||
/* Restricts tree and type comparisons. */
|
||||
int comparing_specializations;
|
||||
int comparing_dependent_aliases;
|
||||
|
||||
/* Returns true iff two spec_entry nodes are equivalent. */
|
||||
|
||||
@ -1718,6 +1719,7 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2)
|
||||
int equal;
|
||||
|
||||
++comparing_specializations;
|
||||
++comparing_dependent_aliases;
|
||||
equal = (e1->tmpl == e2->tmpl
|
||||
&& comp_template_args (e1->args, e2->args));
|
||||
if (equal && flag_concepts
|
||||
@ -1732,6 +1734,7 @@ spec_hasher::equal (spec_entry *e1, spec_entry *e2)
|
||||
tree c2 = e2->spec ? get_constraints (e2->spec) : NULL_TREE;
|
||||
equal = equivalent_constraints (c1, c2);
|
||||
}
|
||||
--comparing_dependent_aliases;
|
||||
--comparing_specializations;
|
||||
|
||||
return equal;
|
||||
@ -6516,7 +6519,11 @@ complex_alias_template_p (const_tree tmpl)
|
||||
tree
|
||||
dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs)
|
||||
{
|
||||
if (!TYPE_P (t) || !typedef_variant_p (t))
|
||||
if (t == error_mark_node)
|
||||
return NULL_TREE;
|
||||
gcc_assert (TYPE_P (t));
|
||||
|
||||
if (!typedef_variant_p (t))
|
||||
return NULL_TREE;
|
||||
|
||||
tree tinfo = TYPE_ALIAS_TEMPLATE_INFO (t);
|
||||
@ -9166,6 +9173,18 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
|
||||
if (class_nttp_const_wrapper_p (ot))
|
||||
ot = TREE_OPERAND (ot, 0);
|
||||
|
||||
/* DR 1558: Don't treat an alias template specialization with dependent
|
||||
arguments as equivalent to its underlying type when used as a template
|
||||
argument; we need them to be distinct so that we substitute into the
|
||||
specialization arguments at instantiation time. And aliases can't be
|
||||
equivalent without being ==, so we don't need to look any deeper.
|
||||
|
||||
During partial ordering, however, we need to treat them normally so we can
|
||||
order uses of the same alias with different cv-qualification (79960). */
|
||||
auto cso = make_temp_override (comparing_dependent_aliases);
|
||||
if (!partial_order)
|
||||
++comparing_dependent_aliases;
|
||||
|
||||
if (TREE_CODE (nt) == TREE_VEC || TREE_CODE (ot) == TREE_VEC)
|
||||
/* For member templates */
|
||||
return TREE_CODE (ot) == TREE_CODE (nt) && comp_template_args (ot, nt);
|
||||
@ -9183,21 +9202,7 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
|
||||
{
|
||||
if (!(TYPE_P (nt) && TYPE_P (ot)))
|
||||
return false;
|
||||
/* Don't treat an alias template specialization with dependent
|
||||
arguments as equivalent to its underlying type when used as a
|
||||
template argument; we need them to be distinct so that we
|
||||
substitute into the specialization arguments at instantiation
|
||||
time. And aliases can't be equivalent without being ==, so
|
||||
we don't need to look any deeper.
|
||||
|
||||
During partial ordering, however, we need to treat them normally so
|
||||
that we can order uses of the same alias with different
|
||||
cv-qualification (79960). */
|
||||
if (!partial_order
|
||||
&& (TYPE_ALIAS_P (nt) || TYPE_ALIAS_P (ot)))
|
||||
return false;
|
||||
else
|
||||
return same_type_p (ot, nt);
|
||||
return same_type_p (ot, nt);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -14903,10 +14908,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||
{
|
||||
DECL_ORIGINAL_TYPE (r) = NULL_TREE;
|
||||
set_underlying_type (r);
|
||||
if (TYPE_DECL_ALIAS_P (r))
|
||||
/* An alias template specialization can be dependent
|
||||
even if its underlying type is not. */
|
||||
TYPE_DEPENDENT_P_VALID (TREE_TYPE (r)) = false;
|
||||
}
|
||||
|
||||
layout_decl (r, 0);
|
||||
@ -21136,6 +21137,17 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
|
||||
tree r = instantiate_template (tmpl, args, complain);
|
||||
pop_tinst_level ();
|
||||
|
||||
if (tree d = dependent_alias_template_spec_p (TREE_TYPE (r), nt_opaque))
|
||||
{
|
||||
/* An alias template specialization can be dependent
|
||||
even if its underlying type is not. */
|
||||
TYPE_DEPENDENT_P (d) = true;
|
||||
TYPE_DEPENDENT_P_VALID (d) = true;
|
||||
/* Sometimes a dependent alias spec is equivalent to its expansion,
|
||||
sometimes not. So always use structural_comptypes. */
|
||||
SET_TYPE_STRUCTURAL_EQUALITY (d);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -3847,12 +3847,7 @@ cp_tree_equal (tree t1, tree t2)
|
||||
template. */
|
||||
|
||||
if (comparing_specializations
|
||||
&& DECL_CONTEXT (t1) != DECL_CONTEXT (t2)
|
||||
/* Module duplicate checking can have t1 = new, t2 =
|
||||
existing, and they should be considered matching at this
|
||||
point. */
|
||||
&& !(DECL_CONTEXT (t1) == map_context_from
|
||||
&& DECL_CONTEXT (t2) == map_context_to))
|
||||
&& DECL_CONTEXT (t1) != DECL_CONTEXT (t2))
|
||||
/* When comparing hash table entries, only an exact match is
|
||||
good enough; we don't want to replace 'this' with the
|
||||
version from another function. But be more flexible
|
||||
|
@ -1251,6 +1251,8 @@ structural_comptypes (tree t1, tree t2, int strict)
|
||||
/* Both should be types that are not obviously the same. */
|
||||
gcc_checking_assert (t1 != t2 && TYPE_P (t1) && TYPE_P (t2));
|
||||
|
||||
/* Suppress typename resolution under spec_hasher::equal in place of calling
|
||||
push_to_top_level there. */
|
||||
if (!comparing_specializations)
|
||||
{
|
||||
/* TYPENAME_TYPEs should be resolved if the qualifying scope is the
|
||||
@ -1483,7 +1485,7 @@ structural_comptypes (tree t1, tree t2, int strict)
|
||||
return false;
|
||||
|
||||
check_alias:
|
||||
if (comparing_specializations)
|
||||
if (comparing_dependent_aliases)
|
||||
{
|
||||
/* Don't treat an alias template specialization with dependent
|
||||
arguments as equivalent to its underlying type when used as a
|
||||
@ -1519,11 +1521,6 @@ comptypes (tree t1, tree t2, int strict)
|
||||
if (t1 == error_mark_node || t2 == error_mark_node)
|
||||
return false;
|
||||
|
||||
if (strict == COMPARE_STRICT && comparing_specializations
|
||||
&& (t1 != TYPE_CANONICAL (t1) || t2 != TYPE_CANONICAL (t2)))
|
||||
/* If comparing_specializations, treat dependent aliases as distinct. */
|
||||
strict = COMPARE_STRUCTURAL;
|
||||
|
||||
if (strict == COMPARE_STRICT)
|
||||
{
|
||||
if (TYPE_STRUCTURAL_EQUALITY_P (t1) || TYPE_STRUCTURAL_EQUALITY_P (t2))
|
||||
|
9
gcc/testsuite/g++.dg/cpp0x/alias-decl-targ1.C
Normal file
9
gcc/testsuite/g++.dg/cpp0x/alias-decl-targ1.C
Normal file
@ -0,0 +1,9 @@
|
||||
// PR c++/98570
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
template <int> struct b { enum { c }; };
|
||||
template <typename> using i = b<0>;
|
||||
|
||||
template <int> struct d { };
|
||||
template <typename l> d<i<l>::c> m() { }
|
||||
template <typename n> d<i<n*>::c> m() { }
|
Loading…
Reference in New Issue
Block a user