From: Reid Kleckner Date: Thu, 8 Oct 2015 21:14:56 +0000 (+0000) Subject: [WinEH] Push cleanupendpad scopes around exceptional cleanups X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e9628e28dadbf03ba7d7fd97f2c62a0d5a6bbd6;p=clang [WinEH] Push cleanupendpad scopes around exceptional cleanups We were only doing this for SEH as a special case. Generalize it to all cleanups. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@249748 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index 5796320894..8bad58d78b 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -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); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 16f6e83647..2c1ede4b76 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -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(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(NormalAndEHCleanup, FinallyFunc, - EHStack.getInnermostEHScope()); + EHStack.pushCleanup(NormalAndEHCleanup, FinallyFunc); return; } diff --git a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp index 27e848b86b..96d8ffe02f 100644 --- a/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp +++ b/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp @@ -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