[clang] 35dcb5c - [CIR] Add EH handling for lifetime extended cleanups (#192305)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 12:53:45 PDT 2026
Author: Andy Kaylor
Date: 2026-04-15T12:53:40-07:00
New Revision: 35dcb5c1303b251d8728bd4f8ed93ff4316eea3a
URL: https://github.com/llvm/llvm-project/commit/35dcb5c1303b251d8728bd4f8ed93ff4316eea3a
DIFF: https://github.com/llvm/llvm-project/commit/35dcb5c1303b251d8728bd4f8ed93ff4316eea3a.diff
LOG: [CIR] Add EH handling for lifetime extended cleanups (#192305)
This adds code to call pushDestroyAndDeferDeactivation from the
pushLifetimeExtendedDestroy function. This was needed to generate the
correct code for lifetime extended cleanups when exceptions are enabled.
An extended version of the cleanup with automatic storage duration is
used as a test case.
To make this work correctly, I had to add a CleanupDeactivationScope to
RunCleanupsScope and force deactivation when forceCleanup is called.
This matches the corresponding code in classic codegen.
I surveyed other places where classic codegen is using
CleanupDeactivationScope and added a MissingFeatures marker in one
location where it was not previously marked. Other places where it was
missing were already marked in this way.
Added:
clang/test/CIR/CodeGen/cleanup-automatic-eh.cpp
Modified:
clang/lib/CIR/CodeGen/CIRGenDecl.cpp
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
clang/lib/CIR/CodeGen/CIRGenFunction.h
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index fcc8564acf341..7e9f6a8a230f3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -1112,15 +1112,10 @@ void CIRGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind,
return;
}
- // Classic codegen also uses pushDestroyAndDeferDeactivation here to push an
- // EH cleanup that protects the temporary during the rest of the full
- // expression, then deactivates it when the full expression ends. Deferred
- // deactivation is being implemented now, but it wasn't when this code was
- // implemented. This will be updated in a separate change.
- if (getLangOpts().Exceptions) {
- cgm.errorNYI("lifetime-extended cleanup with exceptions enabled");
- return;
- }
+ // Add the cleanup to the EHStack. After the full-expr, this would be
+ // deactivated before being popped from the stack.
+ pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer,
+ useEHCleanupForArray);
assert(!cir::MissingFeatures::useEHCleanupForArray());
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index a87cc91037d08..37157e8c2d065 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -726,6 +726,7 @@ void AggExprEmitter::emitArrayInit(Address destPtr, cir::ArrayType arrayTy,
// members if an initializer throws. For that, we'll need an EH cleanup.
QualType::DestructionKind dtorKind = elementType.isDestructedType();
Address endOfInit = Address::invalid();
+ assert(!cir::MissingFeatures::cleanupDeactivationScope());
if (dtorKind && cgf.getLangOpts().Exceptions) {
endOfInit = cgf.createTempAlloca(cirElementPtrType, cgf.getPointerAlign(),
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index efa5527dfa720..7f91cba115f04 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1145,6 +1145,7 @@ class CIRGenFunction : public CIRGenTypeCache {
class RunCleanupsScope {
EHScopeStack::stable_iterator cleanupStackDepth, oldCleanupStackDepth;
size_t lifetimeExtendedCleanupStackSize;
+ CleanupDeactivationScope deactivateCleanups;
protected:
bool performCleanup;
@@ -1160,7 +1161,7 @@ class CIRGenFunction : public CIRGenTypeCache {
public:
/// Enter a new cleanup scope.
explicit RunCleanupsScope(CIRGenFunction &cgf)
- : performCleanup(true), cgf(cgf) {
+ : deactivateCleanups(cgf), performCleanup(true), cgf(cgf) {
cleanupStackDepth = cgf.ehStack.stable_begin();
lifetimeExtendedCleanupStackSize =
cgf.lifetimeExtendedCleanupStack.size();
@@ -1181,6 +1182,7 @@ class CIRGenFunction : public CIRGenTypeCache {
void forceCleanup(ArrayRef<mlir::Value *> valuesToReload = {}) {
assert(performCleanup && "Already forced cleanup");
cgf.didCallStackSave = oldDidCallStackSave;
+ deactivateCleanups.forceDeactivate();
cgf.popCleanupBlocks(cleanupStackDepth, lifetimeExtendedCleanupStackSize,
valuesToReload);
performCleanup = false;
diff --git a/clang/test/CIR/CodeGen/cleanup-automatic-eh.cpp b/clang/test/CIR/CodeGen/cleanup-automatic-eh.cpp
new file mode 100644
index 0000000000000..c6bd774971ef7
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cleanup-automatic-eh.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+struct Struk {
+ Struk();
+ ~Struk();
+};
+
+void mayThrow();
+
+void test_cleanup_with_automatic_storage_duration() {
+ const Struk &ref = Struk{};
+ mayThrow();
+}
+
+// CIR: cir.func{{.*}} @_Z44test_cleanup_with_automatic_storage_durationv()
+// CIR: %[[REF_TMP:.*]] = cir.alloca !rec_Struk, !cir.ptr<!rec_Struk>, ["ref.tmp0"]
+// CIR: %[[REF:.*]] = cir.alloca !cir.ptr<!rec_Struk>, !cir.ptr<!cir.ptr<!rec_Struk>>, ["ref", init, const]
+// CIR: cir.call @_ZN5StrukC1Ev(%[[REF_TMP]])
+// CIR: cir.cleanup.scope {
+// CIR: cir.store{{.*}} %[[REF_TMP]], %[[REF]]
+// CIR: cir.call @_Z8mayThrowv()
+// CIR: cir.yield
+// CIR: } cleanup all {
+// CIR: cir.call @_ZN5StrukD1Ev(%[[REF_TMP]]) nothrow
+// CIR: cir.yield
+// CIR: }
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_Z44test_cleanup_with_automatic_storage_durationv()
+// LLVM: call void @_ZN5StrukC1Ev(
+// LLVM: invoke void @_Z8mayThrowv()
+// LLVM: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
+// LLVM: [[CONT]]:
+// LLVM: call void @_ZN5StrukD1Ev(
+// LLVM: br label %[[EXIT_NORMAL_CLEANUP:.*]]
+// LLVM: [[EXIT_NORMAL_CLEANUP]]:
+// LLVM: br label %[[EXIT:.*]]
+// LLVM: [[LPAD]]:
+// LLVM: landingpad { ptr, i32 }
+// LLVM: cleanup
+// LLVM: call void @_ZN5StrukD1Ev(
+// LLVM: resume
+// LLVM: [[EXIT]]:
+// LLVM: ret void
+
+// OGCG: define {{.*}} void @_Z44test_cleanup_with_automatic_storage_durationv()
+// OGCG: call void @_ZN5StrukC1Ev(
+// OGCG: invoke void @_Z8mayThrowv()
+// OGCG: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
+// OGCG: [[CONT]]:
+// OGCG: call void @_ZN5StrukD1Ev(
+// OGCG: ret void
+// OGCG: [[LPAD]]:
+// OGCG: landingpad { ptr, i32 }
+// OGCG: cleanup
+// OGCG: call void @_ZN5StrukD1Ev(
+// OGCG: resume
More information about the cfe-commits
mailing list