diff options
author | Jason Merrill <jason@redhat.com> | 2021-01-27 17:15:39 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2021-02-01 09:49:42 -0500 |
commit | 6e0a231a4aa2407bb7167daf98a37795a67364d8 (patch) | |
tree | 0683075c4ce5a5cf8691e6eb6cc1a84241a999fa /gcc | |
parent | bec5dbae5649da4bd7ea2731a8446ac481cb78ab (diff) |
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/cp-tree.h | 9 | ||||
-rw-r--r-- | gcc/cp/module.cc | 4 | ||||
-rw-r--r-- | gcc/cp/pt.c | 52 | ||||
-rw-r--r-- | gcc/cp/tree.c | 7 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/alias-decl-targ1.C | 9 |
6 files changed, 53 insertions, 37 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f31319904eb..aed85d79287 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 2d761452505..41ce2011525 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9089afb6ae8..db0ff73bdeb 100644 --- a/gcc/cp/pt.c +++ b/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; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7dcb453ba6a..2e5a1f198e8 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9322e087345..a87d5e5f2ac 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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)) diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-targ1.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-targ1.C new file mode 100644 index 00000000000..dd97479eff9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-targ1.C @@ -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() { } |