const char *RethrowName = Personality.CatchallRethrowFn;
if (RethrowName != nullptr && !isCleanup) {
EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
- getExceptionFromSlot())
- ->setDoesNotReturn();
+ getExceptionFromSlot())->setDoesNotReturn();
Builder.CreateUnreachable();
Builder.restoreIP(SavedIP);
return EHResumeBlock;
Builder.SetInsertPoint(FI.FinallyBB);
EmitStmt(Finally->getBlock());
- // If the finally block doesn't fall through, we don't need these blocks.
- if (!HaveInsertPoint()) {
- FI.ContBB->eraseFromParent();
- if (FI.ResumeBB)
- FI.ResumeBB->eraseFromParent();
- return;
- }
-
- if (FI.ResumeBB) {
- llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
- "abnormal.termination");
- IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
- Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
- } else {
- // There was nothing exceptional in the try body, so we only have normal
- // control flow.
- Builder.CreateBr(FI.ContBB);
+ if (HaveInsertPoint()) {
+ if (FI.ResumeBB) {
+ llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
+ "abnormal.termination");
+ IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
+ Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
+ } else {
+ // There was nothing exceptional in the try body, so we only have normal
+ // control flow.
+ Builder.CreateBr(FI.ContBB);
+ }
}
Builder.restoreIP(SavedIP);
// CHECK-NEXT: br label %[[finally:[^ ]*]]
//
// CHECK: [[finally]]
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: store i8 0, i8* %
+// CHECK-NEXT: store i32 1, i32* %
+// CHECK-NEXT: store i32 1, i32* %
+// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
+//
+// The finally's unreachable continuation block:
+// CHECK: store i32 0, i32* %
+// CHECK-NEXT: br label %[[cleanup]]
+//
+// CHECK: [[cleanup]]
+// CHECK-NEXT: store i8 0, i8* %
// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
//
// CHECK: [[outerfinally]]
// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
//
// CHECK: [[finallycont]]
-// CHECK-NEXT: ret i32 1
+// CHECK-NEXT: %[[dest:[^ ]*]] = load i32* %
+// CHECK-NEXT: switch i32 %[[dest]]
+// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
+//
+// CHECK: [[cleanupcont]]
+// CHECK-NEXT: store i32 0, i32* %
+// CHECK-NEXT: br label %[[return:[^ ]*]]
+//
+// CHECK: [[return]]
+// CHECK-NEXT: %[[reg:[^ ]*]] = load i32* %
+// CHECK-NEXT: ret i32 %[[reg]]
+
+int nested___finally___finally_with_eh_edge() {
+ __try {
+ __try {
+ might_crash();
+ } __finally {
+ return 899;
+ }
+ } __finally {
+ // Intentionally no return here.
+ }
+ return 912;
+}
+// CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
+// CHECK: invoke void @might_crash() #3
+// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[invokecont]]
+// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
+// CHECK-NEXT: br label %[[finally:[^ ]*]]
+
+// CHECK: [[finally]]
+// CHECK-NEXT: store i32 899, i32* %
+// CHECK-NEXT: store i32 1, i32* %
+// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
+//
+// The inner finally's unreachable continuation block:
+// CHECK: store i32 0, i32* %
+// CHECK-NEXT: br label %[[cleanup]]
+//
+// CHECK: [[cleanup]]
+// CHECK-NEXT: store i8 0, i8* %
+// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
+//
+// CHECK: [[outerfinally]]
+// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8* %[[abnormal]]
+// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
+// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
+//
+// CHECK: [[finallycont]]
+// CHECK-NEXT: %[[dest:[^ ]*]] = load i32* %
+// CHECK-NEXT: switch i32 %[[dest]]
+// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
+//
+// CHECK: [[cleanupcont]]
+// CHECK-NEXT: store i32 912, i32* %
+// CHECK-NEXT: br label %[[return:[^ ]*]]
+//
+//
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: store i8 1, i8* %[[abnormal]]
+// CHECK: br label %[[finally]]
+//
+// The inner finally's unreachable resume block:
+// CHECK: store i8 1, i8* %[[abnormal]]
+// CHECK-NEXT: br label %[[outerfinally]]
+//
+// CHECK: [[finallyresume]]
+// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
+//
+// CHECK: [[return]]
+// CHECK-NEXT: %[[reg:[^ ]*]] = load i32* %
+// CHECK-NEXT: ret i32 %[[reg]]
+//
+// The ehresume block, not reachable either.
+// CHECK: [[ehresume]]
+// CHECK: resume
// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
// CHECK-NOT: store i32 23
+// Unused __finally continuation block
+// CHECK: store i32 51, i32* %
+// CHECK-NEXT: br label %[[tryleave]]
+
+// CHECK: [[tryleave]]
+// CHECK-NEXT: br label %[[trycont:[^ ]*]]
+
// CHECK: [[g1_lpad]]
// CHECK: store i8 1, i8* %
// CHECK-NEXT: br label %[[finally]]
// CHECK: br label %[[except:[^ ]*]]
// CHECK: [[except]]
-// CHECK-NEXT: br label %[[trycont:[^ ]*]]
+// CHECK-NEXT: br label %[[trycont]]
// CHECK: [[trycont]]
// CHECK-NEXT: ret i32 1
-// CHECK: [[tryleave]]
-// CHECK-NEXT: br label %[[trycont]]
-
int nested___except___except() {
int myres = 0;
__try {