diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2025-04-13 12:20:37 +1000 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2025-04-16 09:24:00 +1000 |
commit | a6f4178d0d5a51c0de175d282f693f923ffefa27 (patch) | |
tree | 90f82f7e6fa8f02448304ba53cb385ced378b8c6 | |
parent | 674b0875a9861e61544e7040452ac22142db7c8b (diff) | |
download | gcc-a6f4178d0d5a51c0de175d282f693f923ffefa27.zip gcc-a6f4178d0d5a51c0de175d282f693f923ffefa27.tar.gz gcc-a6f4178d0d5a51c0de175d282f693f923ffefa27.tar.bz2 |
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 <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
-rw-r--r-- | gcc/cp/lambda.cc | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/lambda-10_a.H | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/lambda-10_b.C | 7 |
3 files changed, 48 insertions, 0 deletions
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index f0a54b6..b2e0ecd 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 0000000..1ad1a80 --- /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 0000000..3556bce --- /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(); +} |