Index: lib/CodeGen/CGException.cpp =================================================================== --- lib/CodeGen/CGException.cpp +++ lib/CodeGen/CGException.cpp @@ -1707,9 +1707,19 @@ SEHFinallyInfo FI; EnterSEHTryStmt(S, FI); { + JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); + SEHTryEpilogueStack.push_back(&TryExit); + // Disable inlining inside SEH __try scopes. SaveAndRestore Saver(IsSEHTryScope, true); EmitStmt(S.getTryBlock()); + + if (!TryExit.getBlock()->use_empty()) { + EmitBlock(TryExit.getBlock(), /*IsFinished=*/true); + } else { + delete TryExit.getBlock(); + } + SEHTryEpilogueStack.pop_back(); } ExitSEHTryStmt(S, FI); } @@ -1988,5 +1998,13 @@ } void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) { - CGM.ErrorUnsupported(&S, "SEH __leave"); + // If this code is reachable then emit a stop point (if generating + // debug info). We have to do this ourselves because we are on the + // "simple" statement path. + if (HaveInsertPoint()) + EmitStopPoint(&S); + + assert(!SEHTryEpilogueStack.empty() && + "sema should have rejected this __leave"); + EmitBranchThroughCleanup(*SEHTryEpilogueStack.back()); } Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -88,6 +88,7 @@ case Stmt::ContinueStmtClass: case Stmt::DefaultStmtClass: case Stmt::CaseStmtClass: + case Stmt::SEHLeaveStmtClass: llvm_unreachable("should have emitted these statements as simple"); #define STMT(Type, Base) @@ -173,9 +174,6 @@ case Stmt::SEHTryStmtClass: EmitSEHTryStmt(cast(*S)); break; - case Stmt::SEHLeaveStmtClass: - EmitSEHLeaveStmt(cast(*S)); - break; case Stmt::OMPParallelDirectiveClass: EmitOMPParallelDirective(cast(*S)); break; @@ -256,6 +254,7 @@ case Stmt::ContinueStmtClass: EmitContinueStmt(cast(*S)); break; case Stmt::DefaultStmtClass: EmitDefaultStmt(cast(*S)); break; case Stmt::CaseStmtClass: EmitCaseStmt(cast(*S)); break; + case Stmt::SEHLeaveStmtClass: EmitSEHLeaveStmt(cast(*S)); break; } return true; Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -278,6 +278,7 @@ EHScopeStack EHStack; llvm::SmallVector LifetimeExtendedCleanupStack; + llvm::SmallVector SEHTryEpilogueStack; /// Header for data within LifetimeExtendedCleanupStack. struct LifetimeExtendedCleanupHeader { Index: test/CodeGen/exceptions-seh-leave.c =================================================================== --- test/CodeGen/exceptions-seh-leave.c +++ test/CodeGen/exceptions-seh-leave.c @@ -1,19 +1,229 @@ -// RUN: not %clang_cc1 -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s -// This is a codegen test because we only emit the diagnostic when we start -// generating code. +void g(); -int SaveDiv(int numerator, int denominator, int *res) { +////////////////////////////////////////////////////////////////////////////// +// __leave with __except + +// Nothing in the __try block can trap, so __try.cont isn't created. +int __leave_with___except_simple() { int myres = 0; __try { - myres = numerator / denominator; + myres = 15; __leave; + myres = 23; } __except (1) { return 0; } - *res = myres; return 1; } -// CHECK-NOT: error: -// CHECK: error: cannot compile this SEH __leave yet -// CHECK-NOT: error: +// CHECK-LABEL: define i32 @__leave_with___except_simple() +// CHECK: store i32 15, i32* %myres +// CHECK-NEXT: br label %__try.__leave +// CHECK-NOT: store i32 23 +// CHECK: __try.__leave: +// CHECK-NEXT: ret i32 1 + + +// The "normal" case. +int __leave_with___except() { + int myres = 0; + __try { + g(); + __leave; + myres = 23; + } __except (1) { + return 0; + } + return 1; +} +// CHECK-LABEL: define i32 @__leave_with___except() +// CHECK: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} +// For __excepts, instead of an explicit __try.__leave label, we could use +// use invoke.cont as __leave jump target instead. However, not doing this +// keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will +// simplify this anyways. +// CHECK: [[cont]] +// CHECK-NEXT: br label %__try.__leave +// CHECK-NOT: store i32 23 +// CHECK: __try.__leave: +// CHECK-NEXT: br label %__try.cont + + +////////////////////////////////////////////////////////////////////////////// +// __leave with __finally + +void abort(void) __attribute__((noreturn)); + +// Nothing in the __try block can trap, so __finally.cont and friends aren't +// created. +int __leave_with___finally_simple() { + int myres = 0; + __try { + myres = 15; + __leave; + myres = 23; + } __finally { + return 0; + } + return 1; +} +// CHECK-LABEL: define i32 @__leave_with___finally_simple() +// CHECK: store i32 15, i32* %myres +// CHECK-NEXT: br label %__try.__leave +// CHECK-NOT: store i32 23 +// CHECK: __try.__leave: +// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot +// CHECK-NEXT: br label %__finally + +// __finally block doesn't return, __finally.cont doesn't exist. +int __leave_with___finally_noreturn() { + int myres = 0; + __try { + myres = 15; + __leave; + myres = 23; + } __finally { + abort(); + } + return 1; +} +// CHECK-LABEL: define i32 @__leave_with___finally_noreturn() +// CHECK: store i32 15, i32* %myres +// CHECK-NEXT: br label %__try.__leave +// CHECK-NOT: store i32 23 +// CHECK: __try.__leave: +// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot +// CHECK-NEXT: br label %__finally + +// The "normal" case. +int __leave_with___finally() { + int myres = 0; + __try { + g(); + __leave; + myres = 23; + } __finally { + return 0; + } + return 1; +} +// CHECK-LABEL: define i32 @__leave_with___finally() +// CHECK: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-NEXT: to label %[[cont:.*]] unwind label %{{.*}} +// For __finally, there needs to be an explicit __try.__leave, because +// abnormal.termination.slot needs to be set there. +// CHECK: [[cont]] +// CHECK-NEXT: br label %__try.__leave +// CHECK-NOT: store i32 23 +// CHECK: __try.__leave: +// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot +// CHECK-NEXT: br label %__finally + + +////////////////////////////////////////////////////////////////////////////// +// Mixed, nested cases. + +// FIXME: Test with outer __finally once PR22553 is fixed. + +int nested___except___finally() { + int myres = 0; + __try { + __try { + g(); + } __finally { + g(); + __leave; // Refers to the outer __try, not the __finally! + myres = 23; + return 0; + } + + myres = 51; + } __except (1) { + } + return 1; +} +// The order of basic blocks in the below doesn't matter. +// CHECK-LABEL: define i32 @nested___except___finally() + +// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] + +// CHECK: [[g1_cont]]: +// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot +// CHECK-NEXT: br label %__finally + +// CHECK-LABEL: __finally: +// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3 +// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] + +// CHECK: [[g2_cont]]: +// CHECK-NOT: store i32 23 +// CHECK: br label %__try.__leave + +// CHECK: [[g1_lpad]]: +// CHECK: store i8 1, i8* %abnormal.termination.slot +// CHECK-NEXT: br label %__finally + +// CHECK: [[g2_lpad]]: +// CHECK-NOT: %abnormal.termination.slot +// CHECK: br label %__except + +// CHECK-LABEL: __except: +// CHECK-NEXT: br label %__try.cont + +// CHECK-LABEL: __try.__leave: +// CHECK-NEXT: br label %__try.cont + +int nested___except___except() { + int myres = 0; + __try { + __try { + g(); + myres = 16; + } __except (1) { + g(); + __leave; // Refers to the outer __try, not the __except we're in! + myres = 23; + return 0; + } + + myres = 51; + } __except (1) { + } + return 1; +} +// The order of basic blocks in the below doesn't matter. +// CHECK-LABEL: define i32 @nested___except___except() + +// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)() +// CHECK-NEXT: to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] + +// CHECK: [[g1_cont]]: +// CHECK: store i32 16, i32* %myres +// CHECK-NEXT: br label %__try.cont + +// CHECK: [[g1_lpad]]: +// CHECK: br label %__except + +// CHECK-LABEL: __except: +// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3 +// CHECK-NEXT: to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] + +// CHECK: [[g2_cont]]: +// CHECK-NOT: store i32 23 +// CHECK: br label %__try.__leave + +// CHECK: [[g2_lpad]]: +// CHECK: br label %__except3 + +// CHECK-LABEL: __except3: +// CHECK-NEXT: br label %__try.cont4 + +// CHECK-LABEL: __try.cont: +// CHECK-NEXT: store i32 51, i32* %myres +// CHECK-NEXT: br label %__try.__leave + +// CHECK-LABEL: __try.__leave: +// CHECK-NEXT: br label %__try.cont4