On Mon, Apr 14, 2025 at 05:33:05PM -0400, Jason Merrill wrote:
> On 4/13/25 6:32 AM, Nathaniel Shead wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > 
> > -- >8 --
> > 
> > Currently, pruned lambda captures are still leftover in the function's
> > BLOCK and topmost BIND_EXPR; this doesn't cause any issues for normal
> > compilation, but does break modules streaming as we try to reconstruct a
> > FIELD_DECL that no longer exists on the type itself.
> > 
> >     PR c++/119755
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * lambda.cc (prune_lambda_captures): Remove pruned capture from
> >     function's BLOCK_VARS and BIND_EXPR_VARS.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/modules/lambda-10_a.H: New test.
> >     * g++.dg/modules/lambda-10_b.C: New test.
> > 
> > Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
> > ---
> >   gcc/cp/lambda.cc                           | 22 ++++++++++++++++++++++
> >   gcc/testsuite/g++.dg/modules/lambda-10_a.H | 17 +++++++++++++++++
> >   gcc/testsuite/g++.dg/modules/lambda-10_b.C |  7 +++++++
> >   3 files changed, 46 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/modules/lambda-10_a.H
> >   create mode 100644 gcc/testsuite/g++.dg/modules/lambda-10_b.C
> > 
> > diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
> > index f0a54b60275..d01bb04cd32 100644
> > --- a/gcc/cp/lambda.cc
> > +++ b/gcc/cp/lambda.cc
> > @@ -1858,6 +1858,14 @@ prune_lambda_captures (tree body)
> >     cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars);
> > +  tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam)));
> > +  gcc_assert (bind_expr
> > +         && (TREE_CODE (bind_expr) == BIND_EXPR
> > +             /* FIXME: In a noexcept lambda we never prune captures
> > +                (PR119764); when we do we need to handle this case
> > +                for modules streaming.  */
> 
> The attached patch seems to fix that, with the result that your patch
> crashes.
> 

Thanks.  And yup, crashing was deliberate here as I wasn't 100% sure
what the tree would look like for this case after an appropriate fix.

One quick question about your patch, since it could in theory affect ABI
(the size of the lambdas change) should the pruning of such lambdas be
dependent on an ABI version check?

Otherwise here's an updated patch that relies on your patch.
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk along
with yours?  (Or if the potential ABI concerns mean that your change
isn't appropriate for GCC15, would the old version of my patch still be
OK for GCC15 to get 'import std' working again for C++26?)

-- >8 --

Currently, pruned lambda captures are still leftover in the function's
BLOCK and topmost BIND_EXPR; this doesn't cause any issues for normal
compilation, but does break modules streaming as we try to reconstruct a
FIELD_DECL that no longer exists on the type itself.

        PR c++/119755

gcc/cp/ChangeLog:

        * lambda.cc (prune_lambda_captures): Remove pruned capture from
        function's BLOCK_VARS and BIND_EXPR_VARS.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/lambda-10_a.H: New test.
        * g++.dg/modules/lambda-10_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
Reviewed-by: Jason Merrill <ja...@redhat.com>
---
 gcc/cp/lambda.cc                           | 19 +++++++++++++++++++
 gcc/testsuite/g++.dg/modules/lambda-10_a.H | 17 +++++++++++++++++
 gcc/testsuite/g++.dg/modules/lambda-10_b.C |  7 +++++++
 3 files changed, 43 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/lambda-10_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/lambda-10_b.C

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index c6308b941d3..7bb88a900d5 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -1862,6 +1862,11 @@ prune_lambda_captures (tree body)
 
   cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars);
 
+  tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam)));
+  if (bind_expr && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR)
+    bind_expr = expr_single (TREE_OPERAND (bind_expr, 0));
+  gcc_assert (bind_expr && TREE_CODE (bind_expr) == BIND_EXPR);
+
   tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam));
   for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; )
     {
@@ -1883,6 +1888,20 @@ prune_lambda_captures (tree body)
                fieldp = &DECL_CHAIN (*fieldp);
              *fieldp = DECL_CHAIN (*fieldp);
 
+             /* And out of the bindings for the function.  */
+             tree *blockp = &BLOCK_VARS (current_binding_level->blocks);
+             while (*blockp != DECL_EXPR_DECL (**use))
+               blockp = &DECL_CHAIN (*blockp);
+             *blockp = DECL_CHAIN (*blockp);
+
+             /* And maybe out of the vars declared in the containing
+                BIND_EXPR, if it's listed there.  */
+             tree *bindp = &BIND_EXPR_VARS (bind_expr);
+             while (*bindp && *bindp != DECL_EXPR_DECL (**use))
+               bindp = &DECL_CHAIN (*bindp);
+             if (*bindp)
+               *bindp = DECL_CHAIN (*bindp);
+
              /* And remove the capture proxy declaration.  */
              **use = void_node;
              continue;
diff --git a/gcc/testsuite/g++.dg/modules/lambda-10_a.H 
b/gcc/testsuite/g++.dg/modules/lambda-10_a.H
new file mode 100644
index 00000000000..1ad1a808c07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-10_a.H
@@ -0,0 +1,17 @@
+// PR c++/119755
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template <typename _Out> void format(_Out) {
+  constexpr int __term = 1;
+  [&] { __term; };
+  [&] { const int outer = __term; { __term; } };
+  [&]() noexcept { __term; };
+  [&]() noexcept { const int outer = __term; { __term; } };
+  [&](auto) { int n[__term]; }(0);
+  [&](auto) noexcept { int n[__term]; }(0);
+}
+
+inline void vformat() {
+  format(0);
+}
diff --git a/gcc/testsuite/g++.dg/modules/lambda-10_b.C 
b/gcc/testsuite/g++.dg/modules/lambda-10_b.C
new file mode 100644
index 00000000000..3556bcee02c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-10_b.C
@@ -0,0 +1,7 @@
+// PR c++/119755
+// { dg-additional-options "-fmodules" }
+
+import "lambda-10_a.H";
+int main() {
+  vformat();
+}
-- 
2.47.0

Reply via email to