diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -22,6 +22,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGen/CodeGenABITypes.h" +#include "llvm/IR/Instruction.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; @@ -227,13 +228,18 @@ CatchHandler &Handler = Handlers[I]; CGF.EmitBlock(Handler.Block); - llvm::CatchPadInst *CPI = nullptr; - SaveAndRestore RestoreCurrentFuncletPad(CGF.CurrentFuncletPad); - if (useFunclets) - if ((CPI = dyn_cast_or_null(Handler.Block->getFirstNonPHI()))) { + + CodeGenFunction::LexicalScope Cleanups(CGF, Handler.Body->getSourceRange()); + SaveAndRestore RevertAfterScope(CGF.CurrentFuncletPad); + if (useFunclets) { + llvm::Instruction *CPICandidate = Handler.Block->getFirstNonPHI(); + if (auto *CPI = dyn_cast_or_null(CPICandidate)) { CGF.CurrentFuncletPad = CPI; CPI->setOperand(2, CGF.getExceptionSlot().getPointer()); + CGF.EHStack.pushCleanup(NormalCleanup, CPI); } + } + llvm::Value *RawExn = CGF.getExceptionFromSlot(); // Enter the catch. @@ -241,8 +247,6 @@ if (beginCatchFn) Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted"); - CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange()); - if (endCatchFn) { // Add a cleanup to leave the catch. bool EndCatchMightThrow = (Handler.Variable == nullptr); @@ -260,15 +264,13 @@ CGF.EmitAutoVarDecl(*CatchParam); EmitInitOfCatchParam(CGF, CastExn, CatchParam); } - if (CPI) - CGF.EHStack.pushCleanup(NormalCleanup, CPI); CGF.ObjCEHValueStack.push_back(Exn); CGF.EmitStmt(Handler.Body); CGF.ObjCEHValueStack.pop_back(); // Leave any cleanups associated with the catch. - cleanups.ForceCleanup(); + Cleanups.ForceCleanup(); CGF.EmitBranchThroughCleanup(Cont); } diff --git a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm --- a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm +++ b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm @@ -1,29 +1,64 @@ -// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-arc-exceptions -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s // WinEH requires funclet tokens on nounwind intrinsics if they can lower to // regular function calls in the course of IR transformations. // // This is the case for ObjC ARC runtime intrinsics. Test that clang emits the -// funclet tokens for llvm.objc.retain and llvm.objc.storeStrong and that they -// refer to their catchpad's SSA value. +// funclet tokens for llvm.objc.* calls inside catch- and cleanup-pads and that +// they refer to their pad's SSA value. -@class Ety; -void opaque(void); -void test_catch_with_objc_intrinsic(void) { +void do_something(); +void may_throw(id); + +void try_catch_with_objc_intrinsic() { + id ex; @try { - opaque(); - } @catch (Ety *ex) { - // Destroy ex when leaving catchpad. This emits calls to intrinsic functions - // llvm.objc.retain and llvm.objc.storeStrong + may_throw(ex); + } @catch (id ex_caught) { + do_something(); + may_throw(ex_caught); } } -// CHECK-LABEL: define{{.*}} void {{.*}}test_catch_with_objc_intrinsic -// ... -// CHECK: catch.dispatch: -// CHECK-NEXT: [[CATCHSWITCH:%[0-9]+]] = catchswitch within none -// ... -// CHECK: catch: -// CHECK-NEXT: [[CATCHPAD:%[0-9]+]] = catchpad within [[CATCHSWITCH]] -// CHECK: {{%[0-9]+}} = call {{.*}} @llvm.objc.retain{{.*}} [ "funclet"(token [[CATCHPAD]]) ] -// CHECK: call {{.*}} @llvm.objc.storeStrong{{.*}} [ "funclet"(token [[CATCHPAD]]) ] +// CHECK-LABEL: try_catch_with_objc_intrinsic +// +// CHECK: catch.dispatch: +// CHECK-NEXT: [[CATCHSWITCH:%[0-9]+]] = catchswitch within none [label %catch] unwind label %[[CLEANUP1:.*]] +// +// All calls within a catchpad must have funclet tokens that refer to it: +// CHECK: catch: +// CHECK-NEXT: [[CATCHPAD:%[0-9]+]] = catchpad within [[CATCHSWITCH]] +// CHECK: call +// CHECK: @llvm.objc.retain +// CHECK: [ "funclet"(token [[CATCHPAD]]) ] +// CHECK: invoke +// CHECK: do_something +// CHECK: [ "funclet"(token [[CATCHPAD]]) ] +// CHECK: unwind label %[[CLEANUP2:.*]] +// CHECK: invoke +// CHECK: may_throw +// CHECK: [ "funclet"(token [[CATCHPAD]]) ] +// CHECK: unwind label %[[CLEANUP2]] +// CHECK: call +// CHECK: @llvm.objc.storeStrong +// CHECK: [ "funclet"(token [[CATCHPAD]]) ] +// CHECK: catchret from [[CATCHPAD]] to label %catchret.dest +// +// This block exists and it's empty: +// CHECK: catchret.dest: +// CHECK-NEXT: br label %eh.cont +// +// CHECK: [[CLEANUP2]]: +// CHECK-NEXT: [[CLEANUPPAD2:%[0-9]+]] = cleanuppad within [[CATCHPAD]] +// CHECK: call +// CHECK: @llvm.objc.storeStrong +// CHECK: [ "funclet"(token [[CLEANUPPAD2]]) ] +// CHECK: cleanupret from [[CLEANUPPAD2]] +// CHECK: unwind label %[[CLEANUP1]] +// +// CHECK: [[CLEANUP1]]: +// CHECK-NEXT: [[CLEANUPPAD1:%[0-9]+]] = cleanuppad within none +// CHECK: call +// CHECK: @llvm.objc.storeStrong +// CHECK: [ "funclet"(token [[CLEANUPPAD1]]) ] +// CHECK: cleanupret from [[CLEANUPPAD1]] unwind to caller