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>
This commit is contained in:
parent
674b0875a9
commit
a6f4178d0d
3 changed files with 48 additions and 0 deletions
|
@ -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;
|
||||
|
|
17
gcc/testsuite/g++.dg/modules/lambda-10_a.H
Normal file
17
gcc/testsuite/g++.dg/modules/lambda-10_a.H
Normal file
|
@ -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);
|
||||
}
|
7
gcc/testsuite/g++.dg/modules/lambda-10_b.C
Normal file
7
gcc/testsuite/g++.dg/modules/lambda-10_b.C
Normal file
|
@ -0,0 +1,7 @@
|
|||
// PR c++/119755
|
||||
// { dg-additional-options "-fmodules" }
|
||||
|
||||
import "lambda-10_a.H";
|
||||
int main() {
|
||||
vformat();
|
||||
}
|
Loading…
Add table
Reference in a new issue