https://gcc.gnu.org/g:44e31eb265ba1984638908466a88095744a88709

commit r16-149-g44e31eb265ba1984638908466a88095744a88709
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Apr 14 12:18:06 2025 -0400

    c++: pruning non-captures in noexcept lambda [PR119764]
    
    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.
    
    Since this changes captures, it changes the ABI of noexcept lambdas; we
    haven't worked hard to maintain lambda capture ABI, but it's easy enough to
    control here.
    
            PR c++/119764
            PR c++/87185
    
    gcc/cp/ChangeLog:
    
            * lambda.cc (insert_capture_proxy): Handle noexcept lambda.
            (prune_lambda_captures): Likewise, in ABI v21.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/lambda/lambda-noexcept1.C: New test.

Diff:
---
 gcc/cp/lambda.cc                                   | 41 ++++++++++++++--------
 .../g++.dg/cpp0x/lambda/lambda-noexcept1.C         | 10 ++++++
 2 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index b2e0ecdd67eb..a2bed9fb36aa 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);
 }
@@ -1859,11 +1863,10 @@ 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)
+  bool noexcept_p = (bind_expr
+                    && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR);
+  if (noexcept_p)
     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; )
@@ -1872,11 +1875,23 @@ 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.  */
 
+             if (noexcept_p)
+               {
+                 /* We didn't handle noexcept lambda captures correctly before
+                    the fix for PR c++/119764.  */
+                 if (abi_version_crosses (21))
+                   warning_at (location_of (lam), OPT_Wabi, "%qD is no longer"
+                               " captured in noexcept lambda in ABI v21 "
+                               "(GCC 16)", var);
+                 if (!abi_version_at_least (21))
+                   goto next;
+               }
+
              /* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST.  */
              *capp = TREE_CHAIN (cap);
 
@@ -1894,14 +1909,11 @@ prune_lambda_captures (tree body)
 
              /* 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);
-               }
+             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;
@@ -1909,6 +1921,7 @@ prune_lambda_captures (tree body)
            }
        }
 
+    next:
       capp = &TREE_CHAIN (cap);
     }
 }
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 000000000000..d7445569801e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-noexcept1.C
@@ -0,0 +1,10 @@
+// PR c++/119764
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fabi-version=0 -Wabi=20" }
+
+int main() {
+  const int x = 123;
+  auto a = [&]() { return x; };
+  auto b = [&]() noexcept { return x; }; // { dg-warning "no longer captured" }
+  static_assert(sizeof(a) == sizeof(b), "");
+}

Reply via email to