Skip to content

Commit 43c013d

Browse files
author
Patrick Palka
committed
c++: don't substitute TEMPLATE_PARM_CONSTRAINTS [PR100374]
This patch makes us avoid substituting into the TEMPLATE_PARM_CONSTRAINTS of each template parameter except as necessary for declaration matching, like we already do for the other constituent constraints of a declaration. This patch also improves the CA104 implementation of explicit specialization matching of a constrained function template inside a class template, by considering the function's combined constraints instead of just its trailing constraints. This allows us to correctly handle the first three explicit specializations in concepts-spec2.C below, but because we compare the constraints as a whole, it means we incorrectly accept the fourth explicit specialization which writes #3's constraints in a different way. For complete correctness here, determine_specialization should use tsubst_each_template_parm_constraints and template_parameter_heads_equivalent_p. PR c++/100374 gcc/cp/ChangeLog: * pt.cc (determine_specialization): Compare overall constraints not just the trailing constraints. (tsubst_each_template_parm_constraints): Define. (tsubst_friend_function): Use it. (tsubst_friend_class): Use it. (tsubst_template_parm): Don't substitute TEMPLATE_PARM_CONSTRAINTS. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-spec2.C: New test. * g++.dg/cpp2a/concepts-template-parm11.C: New test.
1 parent df4f95d commit 43c013d

File tree

3 files changed

+71
-7
lines changed

3 files changed

+71
-7
lines changed

gcc/cp/pt.cc

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ static int unify_pack_expansion (tree, tree, tree,
184184
tree, unification_kind_t, bool, bool);
185185
static tree copy_template_args (tree);
186186
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
187+
static void tsubst_each_template_parm_constraints (tree, tree, tsubst_flags_t);
187188
tree most_specialized_partial_spec (tree, tsubst_flags_t);
188189
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
189190
static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree);
@@ -2323,8 +2324,8 @@ determine_specialization (tree template_id,
23232324
if (!compparms (fn_arg_types, decl_arg_types))
23242325
continue;
23252326

2326-
tree freq = get_trailing_function_requirements (fn);
2327-
tree dreq = get_trailing_function_requirements (decl);
2327+
tree freq = get_constraints (fn);
2328+
tree dreq = get_constraints (decl);
23282329
if (!freq != !dreq)
23292330
continue;
23302331
if (freq)
@@ -2333,7 +2334,7 @@ determine_specialization (tree template_id,
23332334
constraint-expression. */
23342335
tree fargs = DECL_TI_ARGS (fn);
23352336
tsubst_flags_t complain = tf_none;
2336-
freq = tsubst_constraint (freq, fargs, complain, fn);
2337+
freq = tsubst_constraint_info (freq, fargs, complain, fn);
23372338
if (!cp_tree_equal (freq, dreq))
23382339
continue;
23392340
}
@@ -11240,7 +11241,13 @@ tsubst_friend_function (tree decl, tree args)
1124011241
tree parms = DECL_TEMPLATE_PARMS (new_friend);
1124111242
tree treqs = TEMPLATE_PARMS_CONSTRAINTS (parms);
1124211243
treqs = maybe_substitute_reqs_for (treqs, new_friend);
11243-
TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs;
11244+
if (treqs != TEMPLATE_PARMS_CONSTRAINTS (parms))
11245+
{
11246+
TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs;
11247+
/* As well as each TEMPLATE_PARM_CONSTRAINTS. */
11248+
tsubst_each_template_parm_constraints (parms, args,
11249+
tf_warning_or_error);
11250+
}
1124411251
}
1124511252

1124611253
/* The mangled name for the NEW_FRIEND is incorrect. The function
@@ -11486,6 +11493,8 @@ tsubst_friend_class (tree friend_tmpl, tree args)
1148611493
{
1148711494
tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl),
1148811495
args, tf_warning_or_error);
11496+
tsubst_each_template_parm_constraints (parms, args,
11497+
tf_warning_or_error);
1148911498
location_t saved_input_location = input_location;
1149011499
input_location = DECL_SOURCE_LOCATION (friend_tmpl);
1149111500
tree cons = get_constraints (tmpl);
@@ -11520,6 +11529,8 @@ tsubst_friend_class (tree friend_tmpl, tree args)
1152011529
DECL_FRIEND_CONTEXT (friend_tmpl));
1152111530
--processing_template_decl;
1152211531
set_constraints (tmpl, ci);
11532+
tsubst_each_template_parm_constraints (DECL_TEMPLATE_PARMS (tmpl),
11533+
args, tf_warning_or_error);
1152311534
}
1152411535

1152511536
/* Inject this template into the enclosing namspace scope. */
@@ -13632,21 +13643,38 @@ tsubst_template_parm (tree t, tree args, tsubst_flags_t complain)
1363213643

1363313644
default_value = TREE_PURPOSE (t);
1363413645
parm_decl = TREE_VALUE (t);
13635-
tree constraint = TEMPLATE_PARM_CONSTRAINTS (t);
1363613646

1363713647
parm_decl = tsubst (parm_decl, args, complain, NULL_TREE);
1363813648
if (TREE_CODE (parm_decl) == PARM_DECL
1363913649
&& invalid_nontype_parm_type_p (TREE_TYPE (parm_decl), complain))
1364013650
parm_decl = error_mark_node;
1364113651
default_value = tsubst_template_arg (default_value, args,
1364213652
complain, NULL_TREE);
13643-
constraint = tsubst_constraint (constraint, args, complain, NULL_TREE);
1364413653

1364513654
tree r = build_tree_list (default_value, parm_decl);
13646-
TEMPLATE_PARM_CONSTRAINTS (r) = constraint;
13655+
TEMPLATE_PARM_CONSTRAINTS (r) = TEMPLATE_PARM_CONSTRAINTS (t);
1364713656
return r;
1364813657
}
1364913658

13659+
/* Substitute in-place the TEMPLATE_PARM_CONSTRAINTS of each template
13660+
parameter in PARMS for sake of declaration matching. */
13661+
13662+
static void
13663+
tsubst_each_template_parm_constraints (tree parms, tree args,
13664+
tsubst_flags_t complain)
13665+
{
13666+
++processing_template_decl;
13667+
for (; parms; parms = TREE_CHAIN (parms))
13668+
{
13669+
tree level = TREE_VALUE (parms);
13670+
for (tree parm : tree_vec_range (level))
13671+
TEMPLATE_PARM_CONSTRAINTS (parm)
13672+
= tsubst_constraint (TEMPLATE_PARM_CONSTRAINTS (parm), args,
13673+
complain, NULL_TREE);
13674+
}
13675+
--processing_template_decl;
13676+
}
13677+
1365013678
/* Substitute the ARGS into the indicated aggregate (or enumeration)
1365113679
type T. If T is not an aggregate or enumeration type, it is
1365213680
handled as if by tsubst. IN_DECL is as for tsubst. If
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// { dg-do compile { target c++20 } }
2+
3+
template<class T, int> concept C = true;
4+
5+
template<class T> struct A {
6+
template<C<sizeof(T)> U> void f(); // #1
7+
template<C<0> U> void f(); // #2
8+
template<C<-1> U> void f(); // #3
9+
};
10+
11+
constexpr int n = sizeof(int);
12+
template<> template<C<n> U> void A<int>::f() { } // matches #1
13+
template<> template<C<0> U> void A<int>::f() { } // matches #2
14+
template<> template<C<-2> U> void A<int>::f() { } // no match { dg-error "match" }
15+
template<> template<class U> void A<int>::f() requires C<U, -1> { } // shouldn't match #3
16+
// { dg-error "match" "" { xfail *-*-* } .-1 }
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// PR c++/100374
2+
// { dg-do compile { target c++20 } }
3+
4+
template<class T, class U>
5+
concept C = requires { typename T; };
6+
7+
template<class T>
8+
struct A {
9+
template<C<typename T::value_type> U>
10+
void f();
11+
12+
template<C<typename T::value_type> U>
13+
struct B;
14+
};
15+
16+
int main() {
17+
A<int> a;
18+
a.f<void>();
19+
using type = A<int>::B<void>;
20+
}

0 commit comments

Comments
 (0)