https://github.com/yuxuanchen1997 updated https://github.com/llvm/llvm-project/pull/196597
>From 190653df6b4480e824a079a27089ed847fcb7fdd Mon Sep 17 00:00:00 2001 From: Yuxuan Chen <[email protected]> Date: Thu, 7 May 2026 20:24:49 -0700 Subject: [PATCH] [Clang] Rebind the closure temporary when rebuilding default member initializers Fixes https://github.com/llvm/llvm-project/issues/196469 Since the CWG1815 implementation, `InitListChecker` rebuilds a default member initializer at its point of use in aggregate initialization. The rebuild uses the `EnsureImmediateInvocationInDefaultArgs` tree transform, where `TransformCXXBindTemporaryExpr` strips `CXXBindTemporaryExpr` nodes, relying on the subexpression's rebuild to re-create the temporary binding: every `Rebuild*` path funnels through `Sema::MaybeBindToTemporary`, which also re-registers the cleanup in the current evaluation context. However, the transform overrides `TransformLambdaExpr` to return the closure unchanged (the body is not a subexpression), skipping the `MaybeBindToTemporary` call that `BuildLambdaExpr` ends with. The rebuilt initializer then lacks both the `CXXBindTemporaryExpr` around the closure and the `ExprWithCleanups` marker, so CodeGen never emits the closure's destructor and init-captured members leak. Restore the side effect in the override: re-bind the closure to a temporary, exactly as building the lambda would have. This is a no-op for trivially destructible closures. Co-Authored-By: Claude Fable 5 <[email protected]> --- clang/lib/Sema/SemaExpr.cpp | 12 ++++++++-- ...469-default-member-init-lambda-cleanup.cpp | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGenCXX/gh196469-default-member-init-lambda-cleanup.cpp diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9fd8c6a0a5451..cf1ef0a81185f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5710,9 +5710,17 @@ struct EnsureImmediateInvocationInDefaultArgs // Lambda can only have immediate invocations in the default // args of their parameters, which is transformed upon calling the closure. - // The body is not a subexpression, so we have nothing to do. + // The body is not a subexpression, so we do not transform the lambda + // itself. However, the closure object is returned without rebuilding it, + // so we must redo the effects building a lambda has on the enclosing + // context: any CXXBindTemporaryExpr around it has been dropped by + // TransformCXXBindTemporaryExpr, and the enclosing context must be + // marked as requiring cleanups for the closure's destructor to be run + // at the end of the full-expression. // FIXME: Immediate calls in capture initializers should be transformed. - ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; } + ExprResult TransformLambdaExpr(LambdaExpr *E) { + return SemaRef.MaybeBindToTemporary(E); + } ExprResult TransformBlockExpr(BlockExpr *E) { return E; } // Make sure we don't rebuild the this pointer as it would diff --git a/clang/test/CodeGenCXX/gh196469-default-member-init-lambda-cleanup.cpp b/clang/test/CodeGenCXX/gh196469-default-member-init-lambda-cleanup.cpp new file mode 100644 index 0000000000000..71857dc449416 --- /dev/null +++ b/clang/test/CodeGenCXX/gh196469-default-member-init-lambda-cleanup.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s + +struct Noisy { + Noisy(); + ~Noisy(); +}; + +struct Function { + template <typename F> Function(F) {} +}; + +struct Options { + Function function{[noisy = Noisy{}] {}}; +}; + +Options kOptions{}; + +// CHECK-LABEL: define internal void @__cxx_global_var_init +// CHECK: call void @_ZN5NoisyC1Ev +// CHECK: call void @_ZN8FunctionC1IN7Options8functionMUlvE_EEET_ +// CHECK: call void @_ZN7Options8functionMUlvE_D1Ev + +// CHECK-LABEL: define {{.*}} @_ZN7Options8functionMUlvE_D2Ev +// CHECK: call void @_ZN5NoisyD1Ev _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
