On Thu, 8 Apr 2021, Jason Merrill wrote: > On 4/7/21 12:10 PM, Patrick Palka wrote: > > 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 we need to be able to get at all in-scope template > > parameters and the corresponding template arguments during constraint > > checking of a lambda's op(). And this information is not easily > > available where 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. > > I'm a little surprised you didn't use a TEMPLATE_INFO for these, but this way > is fine too.
Using a TEMPLATE_INFO here works nicely here, I hadn't considered it. Like so? Tested on x86_64-pc-linux-gnu. -- >8 -- Subject: [PATCH] c++: Use a TEMPLATE_INFO to hold regenerated lambda info A TEMPLATE_INFO is a natural fit for what LAMBDA_EXPR_REGENERATED_FROM and LAMBDA_EXPR_REGENERATING_TARGS hold, so let's use it instead. gcc/cp/ChangeLog: * cp-tree.h (LAMBDA_EXPR_REGENERATED_FROM) (LAMBDA_EXPR_REGENERATING_TARGS): Replace these with ... (LAMBDA_EXPR_REGEN_INFO): ... this. (tree_lambda_expr::regenerated_from) (tree_lambda_expr::regenerating_targs): Replace these with ... (tree_lambda_expr::regen_info): ... this. * constraint.cc (satisfy_declaration_constraints): Adjust accordingly. * lambda.c (build_lambda_expr): Likewise. * pt.c (regenerated_lambda_fn_p): Likewise. (most_general_lambda): Likewise. (tsubst_lambda_expr): Likewise. --- gcc/cp/constraint.cc | 4 ++-- gcc/cp/cp-tree.h | 18 +++++++----------- gcc/cp/lambda.c | 3 +-- gcc/cp/pt.c | 15 +++++++++------ 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 0a9d1bfea0f..0ddb2990dd9 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3193,7 +3193,7 @@ satisfy_declaration_constraints (tree t, sat_info info) arguments that were used to regenerate the lambda. */ gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1); tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t)); - tree outer_args = LAMBDA_EXPR_REGENERATING_TARGS (lambda); + tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda)); if (args) args = add_to_template_args (outer_args, args); else @@ -3256,7 +3256,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) /* As in the two-parameter version of this function. */ gcc_assert (TMPL_ARGS_DEPTH (args) == 1); tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t)); - tree outer_args = LAMBDA_EXPR_REGENERATING_TARGS (lambda); + tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda)); args = add_to_template_args (outer_args, args); } else diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bf9d5add0cf..e42b82ae5a4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1456,15 +1456,12 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_PENDING_PROXIES(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->pending_proxies) -/* The immediate LAMBDA_EXPR from which NODE was regenerated, or NULL_TREE - (if NODE was not regenerated via tsubst_lambda_expr). */ -#define LAMBDA_EXPR_REGENERATED_FROM(NODE) \ - (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regenerated_from) - -/* The full set of template arguments used to regenerate NODE, or NULL_TREE - (if NODE was not regenerated via tsubst_lambda_expr). */ -#define LAMBDA_EXPR_REGENERATING_TARGS(NODE) \ - (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regenerating_targs) +/* If NODE was regenerated via tsubst_lambda_expr, this is a TEMPLATE_INFO + whose TI_TEMPLATE is the immediate LAMBDA_EXPR from which NODE was + regenerated, and TI_ARGS is the full set of template arguments used + to regenerate NODE from the most general lambda. */ +#define LAMBDA_EXPR_REGEN_INFO(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info) /* The closure type of the lambda, which is also the type of the LAMBDA_EXPR. */ @@ -1477,8 +1474,7 @@ struct GTY (()) tree_lambda_expr tree capture_list; tree this_capture; tree extra_scope; - tree regenerated_from; - tree regenerating_targs; + tree regen_info; vec<tree, va_gc> *pending_proxies; location_t locus; enum cp_lambda_default_capture_mode_type default_capture_mode : 8; diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index c0a5ffb427e..16e2b4c18b4 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -41,8 +41,7 @@ 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_REGEN_INFO (lambda) = NULL_TREE; LAMBDA_EXPR_PENDING_PROXIES (lambda) = NULL; LAMBDA_EXPR_MUTABLE_P (lambda) = false; return lambda; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index daf1b5aeb32..01c807be1bb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14356,7 +14356,7 @@ regenerated_lambda_fn_p (tree fn) return false; tree closure = DECL_CONTEXT (fn); tree lam = CLASSTYPE_LAMBDA_EXPR (closure); - return LAMBDA_EXPR_REGENERATED_FROM (lam) != NULL_TREE; + return LAMBDA_EXPR_REGEN_INFO (lam) != NULL_TREE; } /* Return the LAMBDA_EXPR from which T was ultimately regenerated. @@ -14365,8 +14365,8 @@ regenerated_lambda_fn_p (tree fn) tree most_general_lambda (tree t) { - while (LAMBDA_EXPR_REGENERATED_FROM (t)) - t = LAMBDA_EXPR_REGENERATED_FROM (t); + while (tree ti = LAMBDA_EXPR_REGEN_INFO (t)) + t = TI_TEMPLATE (ti); return t; } @@ -19278,9 +19278,12 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r) = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t); LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t); - LAMBDA_EXPR_REGENERATED_FROM (r) = t; - LAMBDA_EXPR_REGENERATING_TARGS (r) - = add_to_template_args (LAMBDA_EXPR_REGENERATING_TARGS (t), args); + if (tree ti = LAMBDA_EXPR_REGEN_INFO (t)) + LAMBDA_EXPR_REGEN_INFO (r) + = build_template_info (t, add_to_template_args (TI_ARGS (ti), args)); + else + LAMBDA_EXPR_REGEN_INFO (r) + = build_template_info (t, args); gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL); -- 2.31.1.189.g2e36527f23