aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2025-04-13 12:20:37 +1000
committerNathaniel Shead <nathanieloshead@gmail.com>2025-04-16 09:24:00 +1000
commita6f4178d0d5a51c0de175d282f693f923ffefa27 (patch)
tree90f82f7e6fa8f02448304ba53cb385ced378b8c6
parent674b0875a9861e61544e7040452ac22142db7c8b (diff)
downloadgcc-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.cc24
-rw-r--r--gcc/testsuite/g++.dg/modules/lambda-10_a.H17
-rw-r--r--gcc/testsuite/g++.dg/modules/lambda-10_b.C7
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();
+}