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.

+                 || TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR));
+
    tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam));
    for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; )
      {
@@ -1879,6 +1887,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();
+}
From cd096d37ae49da23d6ee744405dcadf5000bbbcd Mon Sep 17 00:00:00 2001
From: Jason Merrill <ja...@redhat.com>
Date: Mon, 14 Apr 2025 12:18:06 -0400
Subject: [PATCH] c++: pruning non-captures in noexcept lambda [PR119764]
To: gcc-patches@gcc.gnu.org

The patch for PR87185 fixed the ICE without fixing the underlying problem,
that we were failing to find the declaration of the capture proxy that we
are trying to decide whether to prune.  Fixed by looking at the right index
in stmt_list_stack.

	PR c++/119764
	PR c++/87185

gcc/cp/ChangeLog:

	* lambda.cc (insert_capture_proxy): Handle noexcept lambda.
	(prune_lambda_captures): Revert PR87185 patch.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/lambda/lambda-noexcept1.C: New test.
---
 gcc/cp/lambda.cc                                     | 8 ++++++--
 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-noexcept1.C | 9 +++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-noexcept1.C

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index f0a54b60275..c6308b941d3 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -348,7 +348,11 @@ insert_capture_proxy (tree var)
 
   /* And put a DECL_EXPR in the STATEMENT_LIST for the same block.  */
   var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
-  tree stmt_list = (*stmt_list_stack)[1];
+  /* The first stmt_list is from start_preparsed_function.  Then there's a
+     possible stmt_list from begin_eh_spec_block, then the one from the
+     lambda's outer {}.  */
+  unsigned index = 1 + use_eh_spec_block (current_function_decl);
+  tree stmt_list = (*stmt_list_stack)[index];
   gcc_assert (stmt_list);
   append_to_statement_list_force (var, &stmt_list);
 }
@@ -1865,7 +1869,7 @@ prune_lambda_captures (tree body)
       if (tree var = var_to_maybe_prune (cap))
 	{
 	  tree **use = const_vars.get (var);
-	  if (use && TREE_CODE (**use) == DECL_EXPR)
+	  if (TREE_CODE (**use) == DECL_EXPR)
 	    {
 	      /* All uses of this capture were folded away, leaving only the
 		 proxy declaration.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-noexcept1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-noexcept1.C
new file mode 100644
index 00000000000..583fe29dfe0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-noexcept1.C
@@ -0,0 +1,9 @@
+// PR c++/119764
+// { dg-do compile { target c++11 } }
+
+int main() {
+  const int x = 123;
+  auto a = [&]() { return x; };
+  auto b = [&]() noexcept { return x; };
+  static_assert(sizeof(a) == sizeof(b), "");
+}
-- 
2.49.0

Reply via email to