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

Reply via email to