forked from OSchip/llvm-project
[WinEH] Push cleanupendpad scopes around exceptional cleanups
We were only doing this for SEH as a special case. Generalize it to all cleanups. llvm-svn: 249748
This commit is contained in:
parent
5beec213e2
commit
5539152404
|
@ -521,15 +521,6 @@ static void EmitCleanup(CodeGenFunction &CGF,
|
|||
EHScopeStack::Cleanup *Fn,
|
||||
EHScopeStack::Cleanup::Flags flags,
|
||||
Address ActiveFlag) {
|
||||
// Itanium EH cleanups occur within a terminate scope. Microsoft SEH doesn't
|
||||
// have this behavior, and the Microsoft C++ runtime will call terminate for
|
||||
// us if the cleanup throws.
|
||||
bool PushedTerminate = false;
|
||||
if (flags.isForEHCleanup() && !CGF.getTarget().getCXXABI().isMicrosoft()) {
|
||||
CGF.EHStack.pushTerminate();
|
||||
PushedTerminate = true;
|
||||
}
|
||||
|
||||
// If there's an active flag, load it and skip the cleanup if it's
|
||||
// false.
|
||||
llvm::BasicBlock *ContBB = nullptr;
|
||||
|
@ -549,10 +540,6 @@ static void EmitCleanup(CodeGenFunction &CGF,
|
|||
// Emit the continuation block if there was an active flag.
|
||||
if (ActiveFlag.isValid())
|
||||
CGF.EmitBlock(ContBB);
|
||||
|
||||
// Leave the terminate scope.
|
||||
if (PushedTerminate)
|
||||
CGF.EHStack.popTerminate();
|
||||
}
|
||||
|
||||
static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
|
||||
|
@ -931,11 +918,29 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
|
|||
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
|
||||
|
||||
EmitBlock(EHEntry);
|
||||
|
||||
// Push terminate scopes around the potentially throwing destructor calls.
|
||||
// We don't emit these when using funclets, because the runtime does it for
|
||||
// us as part of unwinding out of a cleanuppad.
|
||||
bool PushedTerminate = false;
|
||||
if (!EHPersonality::get(*this).usesFuncletPads()) {
|
||||
EHStack.pushTerminate();
|
||||
PushedTerminate = true;
|
||||
}
|
||||
|
||||
llvm::CleanupPadInst *CPI = nullptr;
|
||||
llvm::BasicBlock *CleanupEndBB = nullptr;
|
||||
llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent);
|
||||
if (EHPersonality::get(*this).usesFuncletPads())
|
||||
if (EHPersonality::get(*this).usesFuncletPads()) {
|
||||
CPI = Builder.CreateCleanupPad({});
|
||||
|
||||
// Build a cleanupendpad to unwind through. Our insertion point should be
|
||||
// in the cleanuppad block.
|
||||
CleanupEndBB = createBasicBlock("ehcleanup.end");
|
||||
CGBuilderTy(*this, CleanupEndBB).CreateCleanupEndPad(CPI, NextAction);
|
||||
EHStack.pushPadEnd(CleanupEndBB);
|
||||
}
|
||||
|
||||
// We only actually emit the cleanup code if the cleanup is either
|
||||
// active or was used before it was deactivated.
|
||||
if (EHActiveFlag.isValid() || IsActive) {
|
||||
|
@ -948,6 +953,21 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
|
|||
else
|
||||
Builder.CreateBr(NextAction);
|
||||
|
||||
// Insert the cleanupendpad block here, if it has any uses.
|
||||
if (CleanupEndBB) {
|
||||
EHStack.popPadEnd();
|
||||
if (CleanupEndBB->hasNUsesOrMore(1)) {
|
||||
CurFn->getBasicBlockList().insertAfter(Builder.GetInsertBlock(),
|
||||
CleanupEndBB);
|
||||
} else {
|
||||
delete CleanupEndBB;
|
||||
}
|
||||
}
|
||||
|
||||
// Leave the terminate scope.
|
||||
if (PushedTerminate)
|
||||
EHStack.popTerminate();
|
||||
|
||||
Builder.restoreIP(SavedIP);
|
||||
|
||||
SimplifyCleanupEntry(*this, EHEntry);
|
||||
|
|
|
@ -1410,10 +1410,8 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
|
|||
namespace {
|
||||
struct PerformSEHFinally final : EHScopeStack::Cleanup {
|
||||
llvm::Function *OutlinedFinally;
|
||||
EHScopeStack::stable_iterator EnclosingScope;
|
||||
PerformSEHFinally(llvm::Function *OutlinedFinally,
|
||||
EHScopeStack::stable_iterator EnclosingScope)
|
||||
: OutlinedFinally(OutlinedFinally), EnclosingScope(EnclosingScope) {}
|
||||
PerformSEHFinally(llvm::Function *OutlinedFinally)
|
||||
: OutlinedFinally(OutlinedFinally) {}
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags F) override {
|
||||
ASTContext &Context = CGF.getContext();
|
||||
|
@ -1438,28 +1436,7 @@ struct PerformSEHFinally final : EHScopeStack::Cleanup {
|
|||
CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
|
||||
/*chainCall=*/false);
|
||||
|
||||
// If this is the normal cleanup, just emit the call.
|
||||
if (!F.isForEHCleanup()) {
|
||||
CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a cleanupendpad to unwind through.
|
||||
llvm::BasicBlock *CleanupBB = CGF.Builder.GetInsertBlock();
|
||||
llvm::BasicBlock *CleanupEndBB = CGF.createBasicBlock("ehcleanup.end");
|
||||
llvm::Instruction *PadInst = CleanupBB->getFirstNonPHI();
|
||||
auto *CPI = cast<llvm::CleanupPadInst>(PadInst);
|
||||
CGBuilderTy(CGF, CleanupEndBB)
|
||||
.CreateCleanupEndPad(CPI, CGF.getEHDispatchBlock(EnclosingScope));
|
||||
|
||||
// Push and pop the cleanupendpad around the call.
|
||||
CGF.EHStack.pushPadEnd(CleanupEndBB);
|
||||
CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
|
||||
CGF.EHStack.popPadEnd();
|
||||
|
||||
// Insert the catchendpad block here.
|
||||
CGF.CurFn->getBasicBlockList().insertAfter(CGF.Builder.GetInsertBlock(),
|
||||
CleanupEndBB);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
@ -1815,8 +1792,7 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
|
|||
HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
|
||||
|
||||
// Push a cleanup for __finally blocks.
|
||||
EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc,
|
||||
EHStack.getInnermostEHScope());
|
||||
EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 %s
|
||||
// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 %s
|
||||
|
||||
struct A {
|
||||
A();
|
||||
|
@ -54,14 +54,14 @@ int HasDeactivatedCleanups() {
|
|||
//
|
||||
// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]])
|
||||
// Destroy the two const ref temporaries.
|
||||
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: ret i32
|
||||
//
|
||||
// Conditionally destroy arg1.
|
||||
// WIN32: %[[cond:.*]] = load i1, i1* %[[isactive]]
|
||||
// WIN32: br i1 %[[cond]]
|
||||
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
|
||||
// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
|
||||
// WIN32: }
|
||||
|
||||
// Test putting the cleanups inside a conditional.
|
||||
|
@ -118,14 +118,14 @@ int HasConditionalDeactivatedCleanups(bool cond) {
|
|||
// False condition.
|
||||
// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
|
||||
// Two normal cleanups for TakeRef args.
|
||||
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: ret i32
|
||||
//
|
||||
// Somewhere in the landing pad soup, we conditionally destroy arg1.
|
||||
// WIN32: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
|
||||
// WIN32: br i1 %[[isactive]]
|
||||
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"
|
||||
// WIN32: }
|
||||
|
||||
namespace crash_on_partial_destroy {
|
||||
|
@ -155,7 +155,7 @@ C::C() { foo(); }
|
|||
// WIN32: getelementptr i8, i8* %{{.*}}, i32 4
|
||||
// WIN32-NOT: load
|
||||
// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"*
|
||||
// WIN32: invoke x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ"
|
||||
// WIN32: call x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ"
|
||||
//
|
||||
// WIN32-NOT: load
|
||||
// WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8*
|
||||
|
@ -188,3 +188,21 @@ void f() {
|
|||
// WIN32-NEXT: cleanuppad
|
||||
// WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}})
|
||||
}
|
||||
|
||||
namespace noexcept_false_dtor {
|
||||
struct D {
|
||||
~D() noexcept(false);
|
||||
};
|
||||
void f() {
|
||||
D d;
|
||||
CouldThrow();
|
||||
}
|
||||
}
|
||||
|
||||
// WIN32-LABEL: define void @"\01?f@noexcept_false_dtor@@YAXXZ"()
|
||||
// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
|
||||
// WIN32: call x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
|
||||
// WIN32: cleanuppad
|
||||
// WIN32: invoke x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
|
||||
// WIN32: cleanupret
|
||||
// WIN32: cleanupendpad
|
||||
|
|
Loading…
Reference in New Issue