https://gcc.gnu.org/g:a6f4178d0d5a51c0de175d282f693f923ffefa27

commit r15-9508-ga6f4178d0d5a51c0de175d282f693f923ffefa27
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Sun Apr 13 12:20:37 2025 +1000

    c++: Prune lambda captures from more places [PR119755]
    
    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>

Diff:
---
 gcc/cp/lambda.cc                           | 24 ++++++++++++++++++++++++
 gcc/testsuite/g++.dg/modules/lambda-10_a.H | 17 +++++++++++++++++
 gcc/testsuite/g++.dg/modules/lambda-10_b.C |  7 +++++++
 3 files changed, 48 insertions(+)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index f0a54b602750..b2e0ecdd67eb 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -1858,6 +1858,13 @@ 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));
+  /* FIXME: We don't currently handle noexcept lambda captures correctly,
+     so bind_expr may not be set; see PR c++/119764.  */
+  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; )
     {
@@ -1879,6 +1886,23 @@ 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.  */
+             if (bind_expr)
+               {
+                 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 000000000000..1ad1a808c07f
--- /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 000000000000..3556bcee02ca
--- /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();
+}

Reply via email to