https://github.com/yuxuanchen1997 updated https://github.com/llvm/llvm-project/pull/196597
>From e39df0f164091095fea19c49dd48a1912fb6acf7 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
