diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-04-08 13:07:43 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-04-08 13:07:43 -0400 |
commit | 123b3e03c911a43054c1f88f5d3110e1d084dd4e (patch) | |
tree | 060c0876ab31fd31f0a892da209e32acdabd178a /gcc/cp/lambda.c | |
parent | 05708d6eef87a3dd0c68b1aed7f8d9c3824062b8 (diff) | |
download | gcc-123b3e03c911a43054c1f88f5d3110e1d084dd4e.zip gcc-123b3e03c911a43054c1f88f5d3110e1d084dd4e.tar.gz gcc-123b3e03c911a43054c1f88f5d3110e1d084dd4e.tar.bz2 |
c++: Don't substitute into constraints on lambdas [PR99874]
We currently substitute through a lambda's constraints whenever we
regenerate it via tsubst_lambda_expr. This is the wrong approach
because it can lead to hard errors due to constraints being evaluated
out of order (as in the testcase concepts-lambda17.C below), and because
it doesn't mesh well with the recently added REQUIRES_EXPR_EXTRA_ARGS
mechanism for delaying substitution into requires-expressions, which is
the cause of this PR.
But in order to avoid substituting through a lambda's constraints during
regeneration, we need to be able to get at all in-scope template
parameters and corresponding template arguments during constraint
checking of a lambda's op(). And this information is not easily
available when we need it, it seems.
To that end, the approach that this patch takes is to add two new fields
to LAMBDA_EXPR (and remove one): LAMBDA_EXPR_REGENERATED_FROM
(replacing LAMBDA_EXPR_INSTANTIATED), and LAMBDA_EXPR_REGENERATING_TARGS.
The former allows us to obtain the complete set of template parameters
that are in-scope for a lambda's op(), and the latter gives us all outer
template arguments that were used to regenerate the lambda (analogous to
the TI_TEMPLATE and TI_ARGS of a TEMPLATE_INFO, respectively).
LAMBDA_EXPR_REGENERATING_TARGS is not strictly necessary -- in an
earlier prototype, I walked LAMBDA_EXPR_EXTRA_SCOPE to build up this set
of outer template arguments on demand, but it seems cleaner to do it this
way. (We'd need to walk LAMBDA_EXPR_EXTRA_SCOPE and not DECL/TYPE_CONTEXT
because the latter skips over variable template scopes.)
This patch also renames the predicate instantiated_lambda_fn_p to
regenerated_lambda_fn_p, for sake of consistency with the rest of the
patch which uses "regenerated" instead of "instantiated".
gcc/cp/ChangeLog:
PR c++/99874
* constraint.cc (get_normalized_constraints_from_decl): Handle
regenerated lambdas.
(satisfy_declaration_constraints): Likewise. Check for
dependent args later.
* cp-tree.h (LAMBDA_EXPR_INSTANTIATED): Replace with ...
(LAMBDA_EXPR_REGENERATED_FROM): ... this.
(LAMBDA_EXPR_REGENERATING_TARGS): New.
(tree_lambda_expr::regenerated_from): New data member.
(tree_lambda_expr::regenerating_targs): New data member.
(add_to_template_args): Declare.
(regenerated_lambda_fn_p): Likewise.
(most_general_lambda): Likewise.
* lambda.c (build_lambda_expr): Set LAMBDA_EXPR_REGENERATED_FROM
and LAMBDA_EXPR_REGENERATING_TARGS.
* pt.c (add_to_template_args): No longer static.
(tsubst_function_decl): Unconditionally propagate constraints on
the substituted function decl.
(instantiated_lambda_fn_p): Rename to ...
(regenerated_lambda_fn_p): ... this. Check
LAMBDA_EXPR_REGENERATED_FROM instead of
LAMBDA_EXPR_INSTANTIATED.
(most_general_lambda): Define.
(enclosing_instantiation_of): Adjust after renaming
instantiated_lambda_fn_p.
(tsubst_lambda_expr): Don't set LAMBDA_EXPR_INSTANTIATED. Set
LAMBDA_EXPR_REGENERATED_FROM and LAMBDA_EXPR_REGENERATING_TARGS.
Don't substitute or set constraints on the regenerated lambda.
gcc/testsuite/ChangeLog:
PR c++/99874
* g++.dg/cpp2a/concepts-lambda16.C: New test.
* g++.dg/cpp2a/concepts-lambda17.C: New test.
Diffstat (limited to 'gcc/cp/lambda.c')
-rw-r--r-- | gcc/cp/lambda.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index b0fd6ec..c0a5ffb 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -41,6 +41,8 @@ build_lambda_expr (void) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE; LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE; LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE; + LAMBDA_EXPR_REGENERATED_FROM (lambda) = NULL_TREE; + LAMBDA_EXPR_REGENERATING_TARGS (lambda) = NULL_TREE; LAMBDA_EXPR_PENDING_PROXIES (lambda) = NULL; LAMBDA_EXPR_MUTABLE_P (lambda) = false; return lambda; |