https://github.com/MuellerMP updated https://github.com/llvm/llvm-project/pull/167176
>From 2af5999c4f8f578ef4fe84d1f35f9ba47dd56d3f Mon Sep 17 00:00:00 2001 From: MuellerMP <[email protected]> Date: Wed, 26 Nov 2025 16:20:12 +0100 Subject: [PATCH] [WinEH] Fix try scopes leaking to caller on inline This fixes issue #164169 When inlining functions compiled with -EHa, try scope terminators might need to be inserted before inlined returns. This prevents leaking try scopes over to the caller. Try scopes can be ended before a ret due to the unwinder forwarding exceptions in the seh epilog to the caller. --- clang/lib/CodeGen/CGException.cpp | 32 +++-- .../windows-seh-EHa-TryScopeTermination1.cpp | 57 ++++++++ .../windows-seh-EHa-TryScopeTermination2.cpp | 132 ++++++++++++++++++ .../windows-seh-EHa-TryScopeTermination3.cpp | 92 ++++++++++++ 4 files changed, 303 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGen/windows-seh-EHa-TryScopeTermination1.cpp create mode 100644 clang/test/CodeGen/windows-seh-EHa-TryScopeTermination2.cpp create mode 100644 clang/test/CodeGen/windows-seh-EHa-TryScopeTermination3.cpp diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index e9d20672ce185..e5420a3a45779 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -45,12 +45,6 @@ static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule &CGM) { return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin"); } -static llvm::FunctionCallee getSehTryEndFn(CodeGenModule &CGM) { - llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); - return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end"); -} - static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { // void __cxa_call_unexpected(void *thrown_exception); @@ -635,6 +629,13 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { ExitCXXTryStmt(S); } +struct TerminateTryScope final : EHScopeStack::Cleanup { + TerminateTryScope() {} + + // this is a noop scope that triggers the scope end emission in CGCleanup + void Emit(CodeGenFunction &CGF, Flags flags) override {} +}; + void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { unsigned NumHandlers = S.getNumHandlers(); EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers); @@ -666,8 +667,11 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler); // Under async exceptions, catch(...) need to catch HW exception too // Mark scope with SehTryBegin as a SEH __try scope - if (getLangOpts().EHAsynch) + if (getLangOpts().EHAsynch) { EmitSehTryScopeBegin(); + // Push cleanup to emit the end of the scope + EHStack.pushCleanup<TerminateTryScope>(NormalCleanup); + } } } } @@ -1211,6 +1215,10 @@ void CodeGenFunction::popCatchScope() { } void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { + // For EHa we might have a cleanup block for the try end + if (EHStack.begin()->getKind() == EHScope::Cleanup) + PopCleanupBlock(); + unsigned NumHandlers = S.getNumHandlers(); EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin()); assert(CatchScope.getNumHandlers() == NumHandlers); @@ -2187,6 +2195,11 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { const SEHExceptStmt *Except = S.getExceptHandler(); assert(Except); EHCatchScope *CatchScope = EHStack.pushCatch(1); + + if (getLangOpts().EHAsynch) { + EHStack.pushCleanup<TerminateTryScope>(NormalCleanup); + } + SEHCodeSlotStack.push_back( CreateMemTemp(getContext().IntTy, "__exception_code")); @@ -2217,9 +2230,8 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { } // IsEHa: emit an invoke _seh_try_end() to mark end of FT flow - if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) { - llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM); - EmitRuntimeCallOrInvoke(SehTryEnd); + if (getLangOpts().EHAsynch) { + PopCleanupBlock(); } // Otherwise, we must have an __except block. diff --git a/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination1.cpp b/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination1.cpp new file mode 100644 index 0000000000000..a648362b3a04f --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination1.cpp @@ -0,0 +1,57 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s +// Check that the try scope of main is properly terminated. +[[noreturn]] void Exit(); + +// CHECK-LABEL: define dso_local noundef i32 @main( +// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__CxxFrameHandler3 { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH:.*]] +// CHECK: [[INVOKE_CONT]]: +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 0 +// CHECK-NEXT: br i1 [[TOBOOL]], label %[[IF_END:.*]], label %[[IF_THEN:.*]] +// CHECK: [[IF_THEN]]: +// CHECK-NEXT: store i32 -1, ptr [[TMP]], align 4 +// CHECK-NEXT: invoke void @_CxxThrowException(ptr [[TMP]], ptr @_TI1H) #[[ATTR4:[0-9]+]] +// CHECK-NEXT: to label %[[UNREACHABLE:.*]] unwind label %[[CATCH_DISPATCH]] +// CHECK: [[IF_END]]: +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[RETVAL]], align 4 +// CHECK-NEXT: invoke void @llvm.seh.scope.end() +// CHECK-NEXT: to label %[[INVOKE_CONT1:.*]] unwind label %[[CATCH_DISPATCH]] +// CHECK: [[CATCH_DISPATCH]]: +// CHECK-NEXT: [[TMP3:%.*]] = catchswitch within none [label %[[CATCH:.*]]] unwind to caller +// CHECK: [[CATCH]]: +// CHECK-NEXT: [[TMP4:%.*]] = catchpad within [[TMP3]] [ptr null, i32 0, ptr null] +// CHECK-NEXT: catchret from [[TMP4]] to label %[[CATCHRET_DEST:.*]] +// CHECK: [[CATCHRET_DEST]]: +// CHECK-NEXT: br label %[[TRY_CONT:.*]] +// CHECK: [[TRY_CONT]]: +// CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR4]] +// CHECK-NEXT: unreachable +// CHECK: [[INVOKE_CONT1]]: +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[RETVAL]], align 4 +// CHECK-NEXT: ret i32 [[TMP5]] +// CHECK: [[UNREACHABLE]]: +// CHECK-NEXT: unreachable +// +int main(int argc, char**) noexcept +{ + try { + if (!argc) { throw -1; } + return argc; + } catch (...) { + } + + Exit(); + return 0; +} diff --git a/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination2.cpp b/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination2.cpp new file mode 100644 index 0000000000000..c479686e8dced --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination2.cpp @@ -0,0 +1,132 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s +// Check that both try scopes containing a return statement are properly terminated. +void DoSth(); +[[noreturn]] void Exit(); + +// CHECK-LABEL: define dso_local noundef i32 @main( +// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__CxxFrameHandler3 { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH6:.*]] +// CHECK: [[INVOKE_CONT]]: +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT1:.*]] unwind label %[[CATCH_DISPATCH:.*]] +// CHECK: [[INVOKE_CONT1]]: +// CHECK-NEXT: invoke void @"?DoSth@@YAXXZ"() +// CHECK-NEXT: to label %[[INVOKE_CONT2:.*]] unwind label %[[CATCH_DISPATCH]] +// CHECK: [[INVOKE_CONT2]]: +// CHECK-NEXT: invoke void @llvm.seh.scope.end() +// CHECK-NEXT: to label %[[INVOKE_CONT3:.*]] unwind label %[[CATCH_DISPATCH]] +// CHECK: [[CATCH_DISPATCH]]: +// CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %[[CATCH:.*]]] unwind label %[[CATCH_DISPATCH6]] +// CHECK: [[CATCH]]: +// CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 0, ptr null] +// CHECK-NEXT: invoke void @llvm.seh.scope.end() [ "funclet"(token [[TMP2]]) ] +// CHECK-NEXT: to label %[[INVOKE_CONT4:.*]] unwind label %[[CATCH_DISPATCH6]] +// CHECK: [[INVOKE_CONT4]]: +// CHECK-NEXT: catchret from [[TMP2]] to label %[[CATCHRET_DEST:.*]] +// CHECK: [[CATCHRET_DEST]]: +// CHECK-NEXT: br label %[[TRY_CONT:.*]] +// CHECK: [[TRY_CONT]]: +// CHECK-NEXT: invoke void @llvm.seh.scope.end() +// CHECK-NEXT: to label %[[INVOKE_CONT5:.*]] unwind label %[[CATCH_DISPATCH6]] +// CHECK: [[CATCH_DISPATCH6]]: +// CHECK-NEXT: [[TMP3:%.*]] = catchswitch within none [label %[[CATCH7:.*]]] unwind to caller +// CHECK: [[CATCH7]]: +// CHECK-NEXT: [[TMP4:%.*]] = catchpad within [[TMP3]] [ptr null, i32 0, ptr null] +// CHECK-NEXT: catchret from [[TMP4]] to label %[[CATCHRET_DEST8:.*]] +// CHECK: [[CATCHRET_DEST8]]: +// CHECK-NEXT: br label %[[TRY_CONT9:.*]] +// CHECK: [[TRY_CONT9]]: +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT10:.*]] unwind label %[[CATCH_DISPATCH19:.*]] +// CHECK: [[INVOKE_CONT10]]: +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT11:.*]] unwind label %[[CATCH_DISPATCH13:.*]] +// CHECK: [[INVOKE_CONT11]]: +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP5]], 0 +// CHECK-NEXT: br i1 [[TOBOOL]], label %[[IF_END:.*]], label %[[IF_THEN:.*]] +// CHECK: [[IF_THEN]]: +// CHECK-NEXT: store i32 -1, ptr [[TMP]], align 4 +// CHECK-NEXT: invoke void @_CxxThrowException(ptr [[TMP]], ptr @_TI1H) #[[ATTR5:[0-9]+]] +// CHECK-NEXT: to label %[[UNREACHABLE:.*]] unwind label %[[CATCH_DISPATCH13]] +// CHECK: [[INVOKE_CONT5]]: +// CHECK-NEXT: br label %[[TRY_CONT9]] +// CHECK: [[INVOKE_CONT3]]: +// CHECK-NEXT: br label %[[TRY_CONT]] +// CHECK: [[IF_END]]: +// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP6]], ptr [[RETVAL]], align 4 +// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-NEXT: invoke void @llvm.seh.scope.end() +// CHECK-NEXT: to label %[[INVOKE_CONT12:.*]] unwind label %[[CATCH_DISPATCH13]] +// CHECK: [[CATCH_DISPATCH13]]: +// CHECK-NEXT: [[TMP7:%.*]] = catchswitch within none [label %[[CATCH14:.*]]] unwind label %[[CATCH_DISPATCH19]] +// CHECK: [[CATCH14]]: +// CHECK-NEXT: [[TMP8:%.*]] = catchpad within [[TMP7]] [ptr null, i32 0, ptr null] +// CHECK-NEXT: invoke void @llvm.seh.scope.end() [ "funclet"(token [[TMP8]]) ] +// CHECK-NEXT: to label %[[INVOKE_CONT15:.*]] unwind label %[[CATCH_DISPATCH19]] +// CHECK: [[INVOKE_CONT15]]: +// CHECK-NEXT: catchret from [[TMP8]] to label %[[CATCHRET_DEST16:.*]] +// CHECK: [[CATCHRET_DEST16]]: +// CHECK-NEXT: br label %[[TRY_CONT17:.*]] +// CHECK: [[TRY_CONT17]]: +// CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-NEXT: br label %[[CLEANUP:.*]] +// CHECK: [[CLEANUP]]: +// CHECK-NEXT: invoke void @llvm.seh.scope.end() +// CHECK-NEXT: to label %[[INVOKE_CONT18:.*]] unwind label %[[CATCH_DISPATCH19]] +// CHECK: [[CATCH_DISPATCH19]]: +// CHECK-NEXT: [[TMP9:%.*]] = catchswitch within none [label %[[CATCH20:.*]]] unwind to caller +// CHECK: [[CATCH20]]: +// CHECK-NEXT: [[TMP10:%.*]] = catchpad within [[TMP9]] [ptr null, i32 0, ptr null] +// CHECK-NEXT: catchret from [[TMP10]] to label %[[CATCHRET_DEST21:.*]] +// CHECK: [[CATCHRET_DEST21]]: +// CHECK-NEXT: br label %[[TRY_CONT22:.*]] +// CHECK: [[TRY_CONT22]]: +// CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR5]] +// CHECK-NEXT: unreachable +// CHECK: [[INVOKE_CONT18]]: +// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label %[[UNREACHABLE]] [ +// CHECK-NEXT: i32 0, label %[[CLEANUP_CONT:.*]] +// CHECK-NEXT: i32 1, label %[[RETURN:.*]] +// CHECK-NEXT: ] +// CHECK: [[CLEANUP_CONT]]: +// CHECK-NEXT: br label %[[TRY_CONT22]] +// CHECK: [[INVOKE_CONT12]]: +// CHECK-NEXT: br label %[[CLEANUP]] +// CHECK: [[RETURN]]: +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[RETVAL]], align 4 +// CHECK-NEXT: ret i32 [[TMP11]] +// CHECK: [[UNREACHABLE]]: +// CHECK-NEXT: unreachable +// +int main(int argc, char**) noexcept +{ + try { + try { + DoSth(); + } catch(...) {} + } catch(...) {} + + try { + try { + if (!argc) { throw -1; } + return argc; + } catch (...) {} + } catch (...) {} + + Exit(); + return 0; +} diff --git a/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination3.cpp b/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination3.cpp new file mode 100644 index 0000000000000..6438a600695ec --- /dev/null +++ b/clang/test/CodeGen/windows-seh-EHa-TryScopeTermination3.cpp @@ -0,0 +1,92 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s +// Check that the both __try scopes containing a return statement are properly terminated. +[[noreturn]] void Exit(); +volatile int *p{nullptr}; + +// CHECK-LABEL: define dso_local noundef i32 @main( +// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] personality ptr @__C_specific_handler { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[__EXCEPTION_CODE:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[__EXCEPTION_CODE1:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH6:.*]] +// CHECK: [[INVOKE_CONT]]: +// CHECK-NEXT: invoke void @llvm.seh.try.begin() +// CHECK-NEXT: to label %[[INVOKE_CONT2:.*]] unwind label %[[CATCH_DISPATCH:.*]] +// CHECK: [[INVOKE_CONT2]]: +// CHECK-NEXT: [[TMP1:%.*]] = load volatile i32, ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 0 +// CHECK-NEXT: br i1 [[TOBOOL]], label %[[IF_END:.*]], label %[[IF_THEN:.*]] +// CHECK: [[IF_THEN]]: +// CHECK-NEXT: [[TMP2:%.*]] = load volatile ptr, ptr @"?p@@3PECHEC", align 8 +// CHECK-NEXT: store volatile i32 0, ptr [[TMP2]], align 4 +// CHECK-NEXT: br label %[[IF_END]] +// CHECK: [[IF_END]]: +// CHECK-NEXT: [[TMP3:%.*]] = load volatile i32, ptr [[ARGC_ADDR]], align 4 +// CHECK-NEXT: store volatile i32 [[TMP3]], ptr [[RETVAL]], align 4 +// CHECK-NEXT: store volatile i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-NEXT: invoke void @llvm.seh.try.end() +// CHECK-NEXT: to label %[[INVOKE_CONT3:.*]] unwind label %[[CATCH_DISPATCH]] +// CHECK: [[CATCH_DISPATCH]]: +// CHECK-NEXT: [[TMP4:%.*]] = catchswitch within none [label %[[__EXCEPT:.*]]] unwind label %[[CATCH_DISPATCH6]] +// CHECK: [[__EXCEPT]]: +// CHECK-NEXT: [[TMP5:%.*]] = catchpad within [[TMP4]] [ptr null] +// CHECK-NEXT: catchret from [[TMP5]] to label %[[__EXCEPT4:.*]] +// CHECK: [[__EXCEPT4]]: +// CHECK-NEXT: [[TMP6:%.*]] = call i32 @llvm.eh.exceptioncode(token [[TMP5]]) +// CHECK-NEXT: store volatile i32 [[TMP6]], ptr [[__EXCEPTION_CODE1]], align 4 +// CHECK-NEXT: br label %[[__TRY_CONT:.*]] +// CHECK: [[__TRY_CONT]]: +// CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-NEXT: br label %[[CLEANUP:.*]] +// CHECK: [[CLEANUP]]: +// CHECK-NEXT: invoke void @llvm.seh.try.end() +// CHECK-NEXT: to label %[[INVOKE_CONT5:.*]] unwind label %[[CATCH_DISPATCH6]] +// CHECK: [[CATCH_DISPATCH6]]: +// CHECK-NEXT: [[TMP7:%.*]] = catchswitch within none [label %[[__EXCEPT7:.*]]] unwind to caller +// CHECK: [[__EXCEPT7]]: +// CHECK-NEXT: [[TMP8:%.*]] = catchpad within [[TMP7]] [ptr null] +// CHECK-NEXT: catchret from [[TMP8]] to label %[[__EXCEPT8:.*]] +// CHECK: [[__EXCEPT8]]: +// CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.eh.exceptioncode(token [[TMP8]]) +// CHECK-NEXT: store i32 [[TMP9]], ptr [[__EXCEPTION_CODE]], align 4 +// CHECK-NEXT: br label %[[__TRY_CONT9:.*]] +// CHECK: [[__TRY_CONT9]]: +// CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR4:[0-9]+]] +// CHECK-NEXT: unreachable +// CHECK: [[INVOKE_CONT5]]: +// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label %[[UNREACHABLE:.*]] [ +// CHECK-NEXT: i32 0, label %[[CLEANUP_CONT:.*]] +// CHECK-NEXT: i32 1, label %[[RETURN:.*]] +// CHECK-NEXT: ] +// CHECK: [[CLEANUP_CONT]]: +// CHECK-NEXT: br label %[[__TRY_CONT9]] +// CHECK: [[INVOKE_CONT3]]: +// CHECK-NEXT: br label %[[CLEANUP]] +// CHECK: [[RETURN]]: +// CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[RETVAL]], align 4 +// CHECK-NEXT: ret i32 [[TMP10]] +// CHECK: [[UNREACHABLE]]: +// CHECK-NEXT: unreachable +// +int main(int argc, char**) noexcept +{ + __try { + __try { + if (!argc) { *p = 0; } + return argc; + } __except(1) {} + } __except(1) {} + + Exit(); + return 0; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
