Skip to content

Commit 0a37463

Browse files
author
Patrick Palka
committed
c++: partial ordering and dep alias tmpl specs [PR90679]
During partial ordering, we want to look through dependent alias template specializations within template arguments and otherwise treat them as opaque in other contexts (see e.g. r7-7116-g0c942f3edab108 and r11-7011-g6e0a231a4aa240). To that end template_args_equal was given a partial_order flag that controls this behavior. This flag does the right thing when a dependent alias template specialization appears as template argument of the partial specialization, e.g. in template<class T, class...> using first_t = T; template<class T> struct traits; template<class T> struct traits<first_t<T, T&>> { }; // #1 template<class T> struct traits<first_t<const T, T&>> { }; // #2 we correctly consider #2 to be more specialized than #1. But if the alias specialization appears as a nested template argument of another class template specialization, e.g. in template<class T> struct traits<A<first_t<T, T&>>> { }; // #1 template<class T> struct traits<A<first_t<const T, T&>>> { }; // #2 then we incorrectly consider #1 and #2 to be unordered. This is because 1. we don't propagate the flag to recursive template_args_equal calls 2. we don't use structural equality for class template specializations written in terms of dependent alias template specializations This patch fixes the first issue by turning the partial_order flag into a global. This patch fixes the second issue by making us propagate structural equality appropriately when building a class template specialization. In passing this patch also improves hashing of specializations that use structural equality. PR c++/90679 gcc/cp/ChangeLog: * cp-tree.h (comp_template_args): Remove partial_order parameter. (template_args_equal): Likewise. * pt.cc (comparing_for_partial_ordering): New global flag. (iterative_hash_template_arg) <case tcc_type>: Hash the template and arguments for specializations that use structural equality. (template_args_equal): Remove partial order parameter and use comparing_for_partial_ordering instead. (comp_template_args): Likewise. (comp_template_args_porder): Set comparing_for_partial_ordering instead. Make static. (any_template_arguments_need_structural_equality_p): Return true for an argument that's a dependent alias template specialization or a class template specialization that itself needs structural equality. * tree.cc (cp_tree_equal) <case TREE_VEC>: Adjust call to comp_template_args. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-75a.C: New test. * g++.dg/cpp0x/alias-decl-75b.C: New test.
1 parent 6d27ee7 commit 0a37463

File tree

5 files changed

+88
-10
lines changed

5 files changed

+88
-10
lines changed

gcc/cp/cp-tree.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7507,8 +7507,8 @@ extern int template_class_depth (tree);
75077507
extern int is_specialization_of (tree, tree);
75087508
extern bool is_specialization_of_friend (tree, tree);
75097509
extern bool comp_template_args (tree, tree, tree * = NULL,
7510-
tree * = NULL, bool = false);
7511-
extern int template_args_equal (tree, tree, bool = false);
7510+
tree * = NULL);
7511+
extern int template_args_equal (tree, tree);
75127512
extern tree maybe_process_partial_specialization (tree);
75137513
extern tree most_specialized_instantiation (tree);
75147514
extern tree most_specialized_partial_spec (tree, tsubst_flags_t, bool = false);

gcc/cp/pt.cc

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,6 +1646,12 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
16461646
int comparing_specializations;
16471647
int comparing_dependent_aliases;
16481648

1649+
/* Whether we are comparing template arguments during partial ordering
1650+
(and therefore want the comparison to look through dependent alias
1651+
template specializations). */
1652+
1653+
static int comparing_for_partial_ordering;
1654+
16491655
/* Returns true iff two spec_entry nodes are equivalent. */
16501656

16511657
bool
@@ -1894,6 +1900,11 @@ iterative_hash_template_arg (tree arg, hashval_t val)
18941900
default:
18951901
if (tree canonical = TYPE_CANONICAL (arg))
18961902
val = iterative_hash_object (TYPE_HASH (canonical), val);
1903+
else if (tree ti = TYPE_TEMPLATE_INFO (arg))
1904+
{
1905+
val = iterative_hash_template_arg (TI_TEMPLATE (ti), val);
1906+
val = iterative_hash_template_arg (TI_ARGS (ti), val);
1907+
}
18971908
break;
18981909
}
18991910

@@ -9322,7 +9333,7 @@ class_nttp_const_wrapper_p (tree t)
93229333
/* Returns 1 if template args OT and NT are equivalent. */
93239334

93249335
int
9325-
template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
9336+
template_args_equal (tree ot, tree nt)
93269337
{
93279338
if (nt == ot)
93289339
return 1;
@@ -9345,7 +9356,7 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
93459356
During partial ordering, however, we need to treat them normally so we can
93469357
order uses of the same alias with different cv-qualification (79960). */
93479358
auto cso = make_temp_override (comparing_dependent_aliases);
9348-
if (!partial_order)
9359+
if (!comparing_for_partial_ordering)
93499360
++comparing_dependent_aliases;
93509361

93519362
if (TREE_CODE (nt) == TREE_VEC || TREE_CODE (ot) == TREE_VEC)
@@ -9393,8 +9404,7 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
93939404

93949405
bool
93959406
comp_template_args (tree oldargs, tree newargs,
9396-
tree *oldarg_ptr /* = NULL */, tree *newarg_ptr /* = NULL */,
9397-
bool partial_order /* = false */)
9407+
tree *oldarg_ptr /* = NULL */, tree *newarg_ptr /* = NULL */)
93989408
{
93999409
if (oldargs == newargs)
94009410
return true;
@@ -9410,7 +9420,7 @@ comp_template_args (tree oldargs, tree newargs,
94109420
tree nt = TREE_VEC_ELT (newargs, i);
94119421
tree ot = TREE_VEC_ELT (oldargs, i);
94129422

9413-
if (! template_args_equal (ot, nt, partial_order))
9423+
if (! template_args_equal (ot, nt))
94149424
{
94159425
if (oldarg_ptr != NULL)
94169426
*oldarg_ptr = ot;
@@ -9422,10 +9432,13 @@ comp_template_args (tree oldargs, tree newargs,
94229432
return true;
94239433
}
94249434

9425-
inline bool
9435+
static bool
94269436
comp_template_args_porder (tree oargs, tree nargs)
94279437
{
9428-
return comp_template_args (oargs, nargs, NULL, NULL, true);
9438+
++comparing_for_partial_ordering;
9439+
bool equal = comp_template_args (oargs, nargs);
9440+
--comparing_for_partial_ordering;
9441+
return equal;
94299442
}
94309443

94319444
/* Implement a freelist interface for objects of type T.
@@ -28727,6 +28740,19 @@ any_template_arguments_need_structural_equality_p (tree args)
2872728740
mutated after the fact by duplicate_decls), so just require
2872828741
structural equality in this case (PR52830). */
2872928742
return true;
28743+
else if (TYPE_P (arg)
28744+
&& TYPE_STRUCTURAL_EQUALITY_P (arg)
28745+
&& dependent_alias_template_spec_p (arg, nt_transparent))
28746+
/* Require structural equality for specializations written
28747+
in terms of a dependent alias template specialization. */
28748+
return true;
28749+
else if (CLASS_TYPE_P (arg)
28750+
&& TYPE_TEMPLATE_INFO (arg)
28751+
&& TYPE_STRUCTURAL_EQUALITY_P (arg))
28752+
/* Require structural equality for specializations written
28753+
in terms of a class template specialization that itself
28754+
needs structural equality. */
28755+
return true;
2873028756
}
2873128757
}
2873228758
}

gcc/cp/tree.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4131,7 +4131,7 @@ cp_tree_equal (tree t1, tree t2)
41314131
case TREE_VEC:
41324132
/* These are template args. Really we should be getting the
41334133
caller to do this as it knows it to be true. */
4134-
if (!comp_template_args (t1, t2, NULL, NULL, false))
4134+
if (!comp_template_args (t1, t2))
41354135
return false;
41364136
return true;
41374137

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// PR c++/90679
2+
// A version of alias-decl-75.C where the specializations of the
3+
// complex alias template first_t are dependent.
4+
// { dg-do compile { target c++11 } }
5+
6+
template<class T, class...>
7+
using first_t = T;
8+
9+
template<class T>
10+
struct A;
11+
12+
template<class T>
13+
struct traits;
14+
15+
template<class T>
16+
struct traits<A<first_t<T, T&>>> {
17+
static constexpr int value = 1;
18+
};
19+
20+
template<class T>
21+
struct traits<A<first_t<const T, T&>>> {
22+
static constexpr int value = 2;
23+
};
24+
25+
static_assert(traits<A<int>>::value == 1, "");
26+
static_assert(traits<A<const int>>::value == 2, ""); // { dg-bogus "ambiguous" }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// PR c++/90679
2+
// A version of alias-decl-75a.C where the alias template specialization
3+
// appears as a more deeply nested template argument.
4+
// { dg-do compile { target c++11 } }
5+
6+
template<class T, class...>
7+
using first_t = T;
8+
9+
template<class T>
10+
struct A;
11+
12+
template<class T>
13+
struct traits;
14+
15+
template<class T>
16+
struct traits<A<A<first_t<T, T&>>>> {
17+
static constexpr int value = 1;
18+
};
19+
20+
template<class T>
21+
struct traits<A<A<first_t<const T, T&>>>> {
22+
static constexpr int value = 2;
23+
};
24+
25+
static_assert(traits<A<A<int>>>::value == 1, "");
26+
static_assert(traits<A<A<const int>>>::value == 2, ""); // { dg-bogus "ambiguous" }

0 commit comments

Comments
 (0)