Skip to content

Commit 686b5eb

Browse files
author
Patrick Palka
committed
c++: requires-exprs and partial constraint subst [PR110006]
In r11-3261-gb28b621ac67bee we made tsubst_requires_expr never partially substitute into a requires-expression so as to avoid checking its requirements out of order during e.g. generic lambda regeneration. These PRs however illustrate that we still sometimes do need to partially substitute into a requires-expression, in particular when it appears in associated constraints that we're directly substituting for sake of declaration matching or dguide constraint rewriting. In these cases we're being called from tsubst_constraint during which processing_constraint_expression_p is true, so this patch checks this predicate to control whether we defer substitution or partially substitute. In turn, we now need to propagate semantic tsubst flags through tsubst_requires_expr rather than just using tf_none, notably for sake of dguide constraint rewriting which sets tf_dguide. PR c++/110006 PR c++/112769 gcc/cp/ChangeLog: * constraint.cc (subst_info::quiet): Accomodate non-diagnostic tsubst flags. (tsubst_valid_expression_requirement): Likewise. (tsubst_simple_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_type_requirement_1): Accomodate non-diagnostic tsubst flags. (tsubst_type_requirement): Return a substituted _REQ node when processing_template_decl. (tsubst_compound_requirement): Likewise. Accomodate non-diagnostic tsubst flags. (tsubst_nested_requirement): Likewise. (tsubst_requires_expr): Don't defer partial substitution when processing_constraint_expression_p is true, in which case return a substituted REQUIRES_EXPR. * pt.cc (tsubst_expr) <case REQUIRES_EXPR>: Accomodate non-diagnostic tsubst flags. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias18.C: New test. * g++.dg/cpp2a/concepts-friend16.C: New test. Reviewed-by: Jason Merrill <[email protected]>
1 parent 64b0130 commit 686b5eb

File tree

4 files changed

+84
-13
lines changed

4 files changed

+84
-13
lines changed

gcc/cp/constraint.cc

+44-12
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ struct subst_info
8585
/* True if we should not diagnose errors. */
8686
bool quiet() const
8787
{
88-
return complain == tf_none;
88+
return !(complain & tf_warning_or_error);
8989
}
9090

9191
/* True if we should diagnose errors. */
@@ -1991,8 +1991,9 @@ hash_placeholder_constraint (tree c)
19911991
static tree
19921992
tsubst_valid_expression_requirement (tree t, tree args, sat_info info)
19931993
{
1994-
tree r = tsubst_expr (t, args, tf_none, info.in_decl);
1995-
if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node)
1994+
tsubst_flags_t quiet = info.complain & ~tf_warning_or_error;
1995+
tree r = tsubst_expr (t, args, quiet, info.in_decl);
1996+
if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node)
19961997
return r;
19971998

19981999
if (info.diagnose_unsatisfaction_p ())
@@ -2028,6 +2029,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info)
20282029
tree expr = tsubst_valid_expression_requirement (t0, args, info);
20292030
if (expr == error_mark_node)
20302031
return error_mark_node;
2032+
if (processing_template_decl)
2033+
return finish_simple_requirement (EXPR_LOCATION (t), expr);
20312034
return boolean_true_node;
20322035
}
20332036

@@ -2037,7 +2040,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info)
20372040
static tree
20382041
tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc)
20392042
{
2040-
tree r = tsubst (t, args, tf_none, info.in_decl);
2043+
tsubst_flags_t quiet = info.complain & ~tf_warning_or_error;
2044+
tree r = tsubst (t, args, quiet, info.in_decl);
20412045
if (r != error_mark_node)
20422046
return r;
20432047

@@ -2068,6 +2072,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info)
20682072
tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t));
20692073
if (type == error_mark_node)
20702074
return error_mark_node;
2075+
if (processing_template_decl)
2076+
return finish_type_requirement (EXPR_LOCATION (t), type);
20712077
return boolean_true_node;
20722078
}
20732079

@@ -2124,9 +2130,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info info)
21242130

21252131
location_t loc = cp_expr_loc_or_input_loc (expr);
21262132

2133+
subst_info quiet (info.complain & ~tf_warning_or_error, info.in_decl);
2134+
21272135
/* Check the noexcept condition. */
21282136
bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
2129-
if (noexcept_p && !expr_noexcept_p (expr, tf_none))
2137+
if (noexcept_p && !expr_noexcept_p (expr, quiet.complain))
21302138
{
21312139
if (info.diagnose_unsatisfaction_p ())
21322140
inform (loc, "%qE is not %<noexcept%>", expr);
@@ -2139,8 +2147,6 @@ tsubst_compound_requirement (tree t, tree args, sat_info info)
21392147
if (type == error_mark_node)
21402148
return error_mark_node;
21412149

2142-
subst_info quiet (tf_none, info.in_decl);
2143-
21442150
/* Check expression against the result type. */
21452151
if (type)
21462152
{
@@ -2182,6 +2188,9 @@ tsubst_compound_requirement (tree t, tree args, sat_info info)
21822188
}
21832189
}
21842190

2191+
if (processing_template_decl)
2192+
return finish_compound_requirement (EXPR_LOCATION (t),
2193+
expr, type, noexcept_p);
21852194
return boolean_true_node;
21862195
}
21872196

@@ -2190,7 +2199,16 @@ tsubst_compound_requirement (tree t, tree args, sat_info info)
21902199
static tree
21912200
tsubst_nested_requirement (tree t, tree args, sat_info info)
21922201
{
2193-
sat_info quiet (tf_none, info.in_decl);
2202+
if (processing_template_decl)
2203+
{
2204+
tree req = TREE_OPERAND (t, 0);
2205+
req = tsubst_constraint (req, args, info.complain, info.in_decl);
2206+
if (req == error_mark_node)
2207+
return error_mark_node;
2208+
return finish_nested_requirement (EXPR_LOCATION (t), req);
2209+
}
2210+
2211+
sat_info quiet (info.complain & ~tf_warning_or_error, info.in_decl);
21942212
tree result = constraint_satisfaction_value (t, args, quiet);
21952213
if (result == boolean_true_node)
21962214
return boolean_true_node;
@@ -2330,37 +2348,51 @@ tsubst_requires_expr (tree t, tree args, sat_info info)
23302348

23312349
args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args,
23322350
info.complain, info.in_decl);
2333-
if (processing_template_decl)
2351+
if (processing_template_decl
2352+
&& !processing_constraint_expression_p ())
23342353
{
23352354
/* We're partially instantiating a generic lambda. Substituting into
23362355
this requires-expression now may cause its requirements to get
23372356
checked out of order, so instead just remember the template
2338-
arguments and wait until we can substitute them all at once. */
2357+
arguments and wait until we can substitute them all at once.
2358+
2359+
Except if this requires-expr is part of associated constraints
2360+
that we're substituting into directly (for e.g. declaration
2361+
matching or dguide constraint rewriting), in which case we need
2362+
to partially substitute. */
23392363
t = copy_node (t);
23402364
REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain);
23412365
return t;
23422366
}
23432367

2344-
if (tree parms = REQUIRES_EXPR_PARMS (t))
2368+
tree parms = REQUIRES_EXPR_PARMS (t);
2369+
if (parms)
23452370
{
23462371
parms = tsubst_constraint_variables (parms, args, info);
23472372
if (parms == error_mark_node)
23482373
return boolean_false_node;
23492374
}
23502375

23512376
tree result = boolean_true_node;
2377+
if (processing_template_decl)
2378+
result = NULL_TREE;
23522379
for (tree reqs = REQUIRES_EXPR_REQS (t); reqs; reqs = TREE_CHAIN (reqs))
23532380
{
23542381
tree req = TREE_VALUE (reqs);
2355-
if (tsubst_requirement (req, args, info) == error_mark_node)
2382+
req = tsubst_requirement (req, args, info);
2383+
if (req == error_mark_node)
23562384
{
23572385
result = boolean_false_node;
23582386
if (info.diagnose_unsatisfaction_p ())
23592387
/* Keep going so that we diagnose all failed requirements. */;
23602388
else
23612389
break;
23622390
}
2391+
else if (processing_template_decl)
2392+
result = tree_cons (NULL_TREE, req, result);
23632393
}
2394+
if (processing_template_decl && result != boolean_false_node)
2395+
result = finish_requires_expr (EXPR_LOCATION (t), parms, nreverse (result));
23642396
return result;
23652397
}
23662398

gcc/cp/pt.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -21706,7 +21706,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
2170621706

2170721707
case REQUIRES_EXPR:
2170821708
{
21709-
tree r = tsubst_requires_expr (t, args, tf_none, in_decl);
21709+
complain &= ~tf_warning_or_error;
21710+
tree r = tsubst_requires_expr (t, args, complain, in_decl);
2171021711
RETURN (r);
2171121712
}
2171221713

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// PR c++/112769
2+
// { dg-do compile { target c++20 } }
3+
4+
template<int I, typename T>
5+
struct type
6+
{
7+
type(T) requires requires { T{0}; };
8+
};
9+
10+
template <typename T>
11+
using alias = type<0, T>;
12+
13+
alias foo{123};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// PR c++/110006
2+
// { dg-do compile { target c++20 } }
3+
4+
template<typename T>
5+
class s;
6+
7+
template<typename T>
8+
void constraint(s<T> const&, int&);
9+
10+
template<typename U, typename T2>
11+
U function(s<T2> const x)
12+
requires requires (U& u) { constraint(x, u); };
13+
14+
template<typename T>
15+
class s
16+
{
17+
template<typename U, typename T2>
18+
friend U function(s<T2> const x)
19+
requires requires (U& u) { constraint(x, u); };
20+
};
21+
22+
int f(s<int> q)
23+
{
24+
return function<int>(q); // { dg-bogus "ambiguous" }
25+
}

0 commit comments

Comments
 (0)