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 7f0edd2138836..2ba5b7730b88c 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 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, ["ref.tmp0"] +// CIR: %[[REF:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["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