diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 812603f7ffe1b..e99517c439743 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -661,6 +661,7 @@ Bug Fixes in This Version - Fixed a crash when ``#embed`` is used with C++ modules (#GH195350) - Fixed an issue where ``__typeof_unqual`` and ``__typeof_unqual__`` were rejected as a declaration specifier in block scope in C++. - Fixed crash when checking for overflow for unary operator that can't overflow (#GH170072) +- Fixed a crash (``Instruction does not dominate all uses`` / broken module) when a block literal capturing variables with non-trivial destructors is used to initialize a block-scope ``static`` or ``thread_local`` variable. The captures' destructors were emitted outside the guarded initialization region, producing invalid IR. (#GH188058) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 57c6bad67dab9..58277c1f1738f 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -216,8 +216,15 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, } bool NeedsDtor = D.needsDestruction(getContext()) == QualType::DK_cxx_destructor; - if (PerformInit) + if (PerformInit) { + // The initializer may push cleanups that are lifetime-extended to the + // enclosing scope (e.g. destructors for block-literal captures). Bound + // them here so they run as part of this initialization instead of + // escaping to the enclosing function, where the on-stack storage they + // reference may not dominate (e.g. under a guarded local-static init). + RunCleanupsScope Scope(*this); EmitDeclInit(*this, D, DeclAddr); + } if (D.getType().isConstantStorage(getContext(), true, !NeedsDtor)) EmitDeclInvariant(*this, D, DeclPtr); else diff --git a/clang/test/CodeGen/block-static-cleanup.cpp b/clang/test/CodeGen/block-static-cleanup.cpp new file mode 100644 index 0000000000000..d64bdc24f2c08 --- /dev/null +++ b/clang/test/CodeGen/block-static-cleanup.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=c++20 -fblocks -emit-llvm -o - %s + +struct S { + ~S(); +}; + +void test() { + S s1, s2; + + static const int i = ^(void) { + (void)s1; + (void)s2; + return 0; + }(); +}