diff options
author | Jason Merrill <jason@redhat.com> | 2025-04-14 12:18:06 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2025-04-25 11:51:07 -0400 |
commit | 44e31eb265ba1984638908466a88095744a88709 (patch) | |
tree | b2fcca467c6ddcbb3a32d937864be7ba84c1db0c /gcc | |
parent | b13bb5045c5010f38169b9786819a024f64fb59d (diff) | |
download | gcc-44e31eb265ba1984638908466a88095744a88709.zip gcc-44e31eb265ba1984638908466a88095744a88709.tar.gz gcc-44e31eb265ba1984638908466a88095744a88709.tar.bz2 |
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/lambda.cc | 41 | ||||
-rw-r--r-- | gcc/testsuite/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 b2e0ecd..a2bed9f 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 0000000..d744556 --- /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), ""); +} |