Skip to content

Commit 1ef74fa

Browse files
committed
[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.
1 parent e493e90 commit 1ef74fa

File tree

7 files changed

+312
-14
lines changed

7 files changed

+312
-14
lines changed

clang/lib/CodeGen/CGCleanup.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,8 +1329,11 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
13291329
// Need to set "funclet" in OperandBundle properly for noThrow
13301330
// intrinsic (see CGCall.cpp)
13311331
static void EmitSehScope(CodeGenFunction &CGF,
1332-
llvm::FunctionCallee &SehCppScope) {
1333-
llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
1332+
llvm::FunctionCallee &SehCppScope,
1333+
llvm::BasicBlock *InvokeDest = nullptr) {
1334+
if (!InvokeDest)
1335+
InvokeDest = CGF.getInvokeDest();
1336+
13341337
assert(CGF.Builder.GetInsertBlock() && InvokeDest);
13351338
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
13361339
SmallVector<llvm::OperandBundleDef, 1> BundleList =
@@ -1373,11 +1376,14 @@ void CodeGenFunction::EmitSehTryScopeBegin() {
13731376
}
13741377

13751378
// Invoke a llvm.seh.try.end at the end of a SEH scope for -EHa
1376-
void CodeGenFunction::EmitSehTryScopeEnd() {
1379+
void CodeGenFunction::EmitSehTryScopeEnd(bool ReuseCachedInvokeDest) {
13771380
assert(getLangOpts().EHAsynch);
13781381
llvm::FunctionType *FTy =
13791382
llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
13801383
llvm::FunctionCallee SehCppScope =
13811384
CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
1382-
EmitSehScope(*this, SehCppScope);
1385+
if (ReuseCachedInvokeDest)
1386+
EmitSehScope(*this, SehCppScope, SehTryEndInvokeDest);
1387+
else
1388+
EmitSehScope(*this, SehCppScope);
13831389
}

clang/lib/CodeGen/CGException.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -635,14 +635,23 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
635635
ExitCXXTryStmt(S);
636636
}
637637

638+
struct TerminateTryScope final : EHScopeStack::Cleanup {
639+
void Emit(CodeGenFunction &CGF, Flags flags) override {
640+
CGF.EmitSehTryScopeEnd(true);
641+
}
642+
};
643+
644+
struct HandlerInfo {
645+
CatchTypeInfo TypeInfo;
646+
bool RequiresSehScope;
647+
};
648+
638649
void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
639650
unsigned NumHandlers = S.getNumHandlers();
640-
EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
641-
651+
unsigned NumHandlerInfos = NumHandlers > 0 ? NumHandlers - 1 : 0;
652+
llvm::SmallVector<HandlerInfo> HandlerInfos{NumHandlerInfos};
642653
for (unsigned I = 0; I != NumHandlers; ++I) {
643654
const CXXCatchStmt *C = S.getHandler(I);
644-
645-
llvm::BasicBlock *Handler = createBasicBlock("catch");
646655
if (C->getExceptionDecl()) {
647656
// FIXME: Dropping the reference type on the type into makes it
648657
// impossible to correctly implement catch-by-reference
@@ -660,14 +669,30 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
660669
else
661670
TypeInfo = CGM.getCXXABI().getAddrOfCXXCatchHandlerType(
662671
CaughtType, C->getCaughtType());
663-
CatchScope->setHandler(I, TypeInfo, Handler);
672+
HandlerInfos.push_back({TypeInfo, false});
664673
} else {
674+
bool HasEHa = getLangOpts().EHAsynch;
665675
// No exception decl indicates '...', a catch-all.
666-
CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler);
676+
HandlerInfos.push_back({CGM.getCXXABI().getCatchAllTypeInfo(), HasEHa});
677+
// Push, if needed, a terminator for the created SEH __try scope
678+
if (HasEHa && !SehTryEndInvokeDest) {
679+
EHStack.pushCleanup<TerminateTryScope>(NormalCleanup);
680+
}
681+
}
682+
}
683+
684+
EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
685+
686+
for (unsigned I = 0; I < HandlerInfos.size(); ++I) {
687+
llvm::BasicBlock *Handler = createBasicBlock("catch");
688+
auto HandlerInfo = HandlerInfos[I];
689+
CatchScope->setHandler(I, HandlerInfo.TypeInfo, Handler);
690+
if (HandlerInfo.RequiresSehScope) {
667691
// Under async exceptions, catch(...) need to catch HW exception too
668692
// Mark scope with SehTryBegin as a SEH __try scope
669-
if (getLangOpts().EHAsynch)
670-
EmitSehTryScopeBegin();
693+
EmitSehTryScopeBegin();
694+
if (!SehTryEndInvokeDest)
695+
SehTryEndInvokeDest = getInvokeDest();
671696
}
672697
}
673698
}
@@ -1675,6 +1700,8 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
16751700
EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
16761701
if (SEHTryEpilogueStack.size() == 1) // outermost only
16771702
TryBB = Builder.GetInsertBlock();
1703+
if (!SehTryEndInvokeDest)
1704+
SehTryEndInvokeDest = getInvokeDest();
16781705
}
16791706

16801707
EmitStmt(S.getTryBlock());
@@ -2186,6 +2213,10 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
21862213
// Otherwise, we must have an __except block.
21872214
const SEHExceptStmt *Except = S.getExceptHandler();
21882215
assert(Except);
2216+
2217+
if (getLangOpts().EHAsynch && !SehTryEndInvokeDest)
2218+
EHStack.pushCleanup<TerminateTryScope>(NormalCleanup);
2219+
21892220
EHCatchScope *CatchScope = EHStack.pushCatch(1);
21902221
SEHCodeSlotStack.push_back(
21912222
CreateMemTemp(getContext().IntTy, "__exception_code"));

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2129,6 +2129,9 @@ class CodeGenFunction : public CodeGenTypeCache {
21292129
/// Terminate funclets keyed by parent funclet pad.
21302130
llvm::MapVector<llvm::Value *, llvm::BasicBlock *> TerminateFunclets;
21312131

2132+
/// Unwind destination for try scope end.
2133+
llvm::BasicBlock *SehTryEndInvokeDest = nullptr;
2134+
21322135
/// Largest vector width used in ths function. Will be used to create a
21332136
/// function attribute.
21342137
unsigned LargestVectorWidth = 0;
@@ -3241,7 +3244,7 @@ class CodeGenFunction : public CodeGenTypeCache {
32413244
void EmitSehCppScopeBegin();
32423245
void EmitSehCppScopeEnd();
32433246
void EmitSehTryScopeBegin();
3244-
void EmitSehTryScopeEnd();
3247+
void EmitSehTryScopeEnd(bool ReuseCachedInvokeDest = false);
32453248

32463249
bool EmitLifetimeStart(llvm::Value *Addr);
32473250
void EmitLifetimeEnd(llvm::Value *Addr);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
2+
// RUN: %clang_cc1 -O3 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s
3+
// Check that the try scope of ExitOnThrow is terminated upon inlining into main.
4+
int AlwaysThrows(int);
5+
[[noreturn]] void Exit();
6+
7+
int ExitOnThrow(int argc) noexcept
8+
{
9+
try {
10+
if (!argc) { throw -1; }
11+
return argc;
12+
} catch (...) {
13+
}
14+
15+
Exit();
16+
return 0;
17+
}
18+
19+
// CHECK-LABEL: define dso_local noundef i32 @main(
20+
// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] personality ptr @__CxxFrameHandler3 {
21+
// CHECK-NEXT: [[ENTRY:.*:]]
22+
// CHECK-NEXT: [[TMP_I:%.*]] = alloca i32, align 4
23+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TMP_I]])
24+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
25+
// CHECK-NEXT: to label %[[INVOKE_CONT_I:.*]] unwind label %[[CATCH_DISPATCH_I:.*]]
26+
// CHECK: [[INVOKE_CONT_I]]:
27+
// CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC]], 0
28+
// CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label %[[IF_END_I:.*]]
29+
// CHECK: [[IF_THEN_I]]:
30+
// CHECK-NEXT: store i32 -1, ptr [[TMP_I]], align 4, !tbaa [[INT_TBAA7:![0-9]+]]
31+
// CHECK-NEXT: invoke void @_CxxThrowException(ptr nonnull [[TMP_I]], ptr nonnull @_TI1H) #[[ATTR6:[0-9]+]]
32+
// CHECK-NEXT: to label %[[UNREACHABLE_I:.*]] unwind label %[[CATCH_DISPATCH_I]]
33+
// CHECK: [[CATCH_DISPATCH_I]]:
34+
// CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %[[CATCH_I:.*]]] unwind to caller
35+
// CHECK: [[CATCH_I]]:
36+
// CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 0, ptr null]
37+
// CHECK-NEXT: catchret from [[TMP2]] to label %[[TRY_CONT_I:.*]]
38+
// CHECK: [[TRY_CONT_I]]:
39+
// CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR7:[0-9]+]]
40+
// CHECK-NEXT: unreachable
41+
// CHECK: [[IF_END_I]]:
42+
// CHECK-NEXT: invoke void @llvm.seh.try.end()
43+
// CHECK-NEXT: to label %"?ExitOnThrow@@[email protected]" unwind label %[[CATCH_DISPATCH_I]]
44+
// CHECK: [[UNREACHABLE_I]]:
45+
// CHECK-NEXT: unreachable
46+
// CHECK: "?ExitOnThrow@@[email protected]":
47+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TMP_I]])
48+
// CHECK-NEXT: [[CALL1:%.*]] = tail call noundef i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC]])
49+
// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC]]
50+
// CHECK-NEXT: ret i32 [[ADD]]
51+
//
52+
int main(int argc, char**)
53+
{
54+
auto data = ExitOnThrow(argc);
55+
return data + AlwaysThrows(data);
56+
}
57+
//.
58+
// CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
59+
// CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0}
60+
// CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0}
61+
// CHECK: [[META10]] = !{!"Simple C++ TBAA"}
62+
//.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
2+
// RUN: %clang_cc1 -O3 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s
3+
// Check that only the outermost try scope containing a return statement is terminated upon inlining into main.
4+
void DoSth();
5+
int AlwaysThrows(int);
6+
[[noreturn]] void Exit();
7+
8+
int ExitOnThrow(int argc) noexcept
9+
{
10+
try {
11+
try {
12+
DoSth();
13+
} catch(...) {}
14+
} catch(...) {}
15+
16+
try {
17+
try {
18+
if (!argc) { throw -1; }
19+
return argc;
20+
} catch (...) {}
21+
} catch (...) {}
22+
23+
Exit();
24+
return 0;
25+
}
26+
27+
// CHECK-LABEL: define dso_local noundef i32 @main(
28+
// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] personality ptr @__CxxFrameHandler3 {
29+
// CHECK-NEXT: [[ENTRY:.*:]]
30+
// CHECK-NEXT: [[TMP_I:%.*]] = alloca i32, align 4
31+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TMP_I]])
32+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
33+
// CHECK-NEXT: to label %[[INVOKE_CONT_I:.*]] unwind label %[[CATCH_DISPATCH4_I:.*]]
34+
// CHECK: [[INVOKE_CONT_I]]:
35+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
36+
// CHECK-NEXT: to label %[[INVOKE_CONT1_I:.*]] unwind label %[[CATCH_DISPATCH_I:.*]]
37+
// CHECK: [[INVOKE_CONT1_I]]:
38+
// CHECK-NEXT: invoke void @"?DoSth@@YAXXZ"()
39+
// CHECK-NEXT: to label %[[TRY_CONT7_I:.*]] unwind label %[[CATCH_DISPATCH_I]]
40+
// CHECK: [[CATCH_DISPATCH_I]]:
41+
// CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %[[CATCH_I:.*]]] unwind label %[[CATCH_DISPATCH4_I]]
42+
// CHECK: [[CATCH_I]]:
43+
// CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 0, ptr null]
44+
// CHECK-NEXT: invoke void @llvm.seh.scope.end() [ "funclet"(token [[TMP2]]) ]
45+
// CHECK-NEXT: to label %[[INVOKE_CONT3_I:.*]] unwind label %[[CATCH_DISPATCH4_I]]
46+
// CHECK: [[CATCH_DISPATCH4_I]]:
47+
// CHECK-NEXT: [[TMP3:%.*]] = catchswitch within none [label %[[CATCH5_I:.*]]] unwind to caller
48+
// CHECK: [[CATCH5_I]]:
49+
// CHECK-NEXT: [[TMP4:%.*]] = catchpad within [[TMP3]] [ptr null, i32 0, ptr null]
50+
// CHECK-NEXT: catchret from [[TMP4]] to label %[[TRY_CONT7_I]]
51+
// CHECK: [[TRY_CONT7_I]]:
52+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
53+
// CHECK-NEXT: to label %[[INVOKE_CONT8_I:.*]] unwind label %[[CATCH_DISPATCH15_I:.*]]
54+
// CHECK: [[INVOKE_CONT8_I]]:
55+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
56+
// CHECK-NEXT: to label %[[INVOKE_CONT9_I:.*]] unwind label %[[CATCH_DISPATCH10_I:.*]]
57+
// CHECK: [[INVOKE_CONT9_I]]:
58+
// CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC]], 0
59+
// CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label %[[IF_END_I:.*]]
60+
// CHECK: [[IF_THEN_I]]:
61+
// CHECK-NEXT: store i32 -1, ptr [[TMP_I]], align 4, !tbaa [[INT_TBAA7:![0-9]+]]
62+
// CHECK-NEXT: invoke void @_CxxThrowException(ptr nonnull [[TMP_I]], ptr nonnull @_TI1H) #[[ATTR7:[0-9]+]]
63+
// CHECK-NEXT: to label %[[UNREACHABLE_I:.*]] unwind label %[[CATCH_DISPATCH10_I]]
64+
// CHECK: [[CATCH_DISPATCH10_I]]:
65+
// CHECK-NEXT: [[TMP5:%.*]] = catchswitch within none [label %[[CATCH11_I:.*]]] unwind label %[[CATCH_DISPATCH15_I]]
66+
// CHECK: [[CATCH11_I]]:
67+
// CHECK-NEXT: [[TMP6:%.*]] = catchpad within [[TMP5]] [ptr null, i32 0, ptr null]
68+
// CHECK-NEXT: invoke void @llvm.seh.scope.end() [ "funclet"(token [[TMP6]]) ]
69+
// CHECK-NEXT: to label %[[INVOKE_CONT12_I:.*]] unwind label %[[CATCH_DISPATCH15_I]]
70+
// CHECK: [[CATCH_DISPATCH15_I]]:
71+
// CHECK-NEXT: [[TMP7:%.*]] = catchswitch within none [label %[[CATCH16_I:.*]]] unwind to caller
72+
// CHECK: [[CATCH16_I]]:
73+
// CHECK-NEXT: [[TMP8:%.*]] = catchpad within [[TMP7]] [ptr null, i32 0, ptr null]
74+
// CHECK-NEXT: catchret from [[TMP8]] to label %[[TRY_CONT18_I:.*]]
75+
// CHECK: [[TRY_CONT18_I]]:
76+
// CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR8:[0-9]+]]
77+
// CHECK-NEXT: unreachable
78+
// CHECK: [[INVOKE_CONT12_I]]:
79+
// CHECK-NEXT: catchret from [[TMP6]] to label %[[TRY_CONT18_I]]
80+
// CHECK: [[INVOKE_CONT3_I]]:
81+
// CHECK-NEXT: catchret from [[TMP2]] to label %[[TRY_CONT7_I]]
82+
// CHECK: [[IF_END_I]]:
83+
// CHECK-NEXT: invoke void @llvm.seh.try.end()
84+
// CHECK-NEXT: to label %"?ExitOnThrow@@[email protected]" unwind label %[[CATCH_DISPATCH4_I]]
85+
// CHECK: [[UNREACHABLE_I]]:
86+
// CHECK-NEXT: unreachable
87+
// CHECK: "?ExitOnThrow@@[email protected]":
88+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TMP_I]])
89+
// CHECK-NEXT: [[CALL1:%.*]] = tail call noundef i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC]])
90+
// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC]]
91+
// CHECK-NEXT: ret i32 [[ADD]]
92+
//
93+
int main(int argc, char**)
94+
{
95+
auto data = ExitOnThrow(argc);
96+
return data + AlwaysThrows(data);
97+
}
98+
//.
99+
// CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
100+
// CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0}
101+
// CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0}
102+
// CHECK: [[META10]] = !{!"Simple C++ TBAA"}
103+
//.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
2+
// RUN: %clang_cc1 -O3 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm %s -o - | FileCheck %s
3+
// Check that the outermost __try scope containing a return statement is terminated upon inlining into main.
4+
int AlwaysThrows(int);
5+
[[noreturn]] void Exit();
6+
volatile int *p{nullptr};
7+
8+
int ExitOnThrow(int argc) noexcept
9+
{
10+
__try {
11+
__try {
12+
if (!argc) { *p = 0; }
13+
return argc;
14+
} __except(1) {}
15+
} __except(1) {}
16+
17+
Exit();
18+
return 0;
19+
}
20+
21+
// CHECK-LABEL: define dso_local noundef i32 @main(
22+
// CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] personality ptr @__C_specific_handler {
23+
// CHECK-NEXT: [[ENTRY:.*:]]
24+
// CHECK-NEXT: [[ARGC_ADDR_I:%.*]] = alloca i32, align 4
25+
// CHECK-NEXT: [[__EXCEPTION_CODE1_I:%.*]] = alloca i32, align 4
26+
// CHECK-NEXT: [[CLEANUP_DEST_SLOT_I:%.*]] = alloca i32, align 4
27+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[ARGC_ADDR_I]])
28+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[__EXCEPTION_CODE1_I]])
29+
// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[CLEANUP_DEST_SLOT_I]])
30+
// CHECK-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR_I]], align 4, !tbaa [[INT_TBAA7:![0-9]+]]
31+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
32+
// CHECK-NEXT: to label %[[INVOKE_CONT_I:.*]] unwind label %[[CATCH_DISPATCH5_I:.*]]
33+
// CHECK: [[INVOKE_CONT_I]]:
34+
// CHECK-NEXT: invoke void @llvm.seh.try.begin()
35+
// CHECK-NEXT: to label %[[INVOKE_CONT2_I:.*]] unwind label %[[CATCH_DISPATCH_I:.*]]
36+
// CHECK: [[CATCH_DISPATCH_I]]:
37+
// CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %[[__EXCEPT_I:.*]]] unwind label %[[CATCH_DISPATCH5_I]]
38+
// CHECK: [[__EXCEPT_I]]:
39+
// CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null]
40+
// CHECK-NEXT: catchret from [[TMP2]] to label %[[__EXCEPT3_I:.*]]
41+
// CHECK: [[__EXCEPT3_I]]:
42+
// CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @llvm.eh.exceptioncode(token [[TMP2]])
43+
// CHECK-NEXT: store volatile i32 [[TMP3]], ptr [[__EXCEPTION_CODE1_I]], align 4
44+
// CHECK-NEXT: invoke void @llvm.seh.try.end()
45+
// CHECK-NEXT: to label %[[__TRY_CONT8_I:.*]] unwind label %[[CATCH_DISPATCH5_I]]
46+
// CHECK: [[CATCH_DISPATCH5_I]]:
47+
// CHECK-NEXT: [[TMP4:%.*]] = catchswitch within none [label %[[__EXCEPT6_I:.*]]] unwind to caller
48+
// CHECK: [[__EXCEPT6_I]]:
49+
// CHECK-NEXT: [[TMP5:%.*]] = catchpad within [[TMP4]] [ptr null]
50+
// CHECK-NEXT: catchret from [[TMP5]] to label %[[__EXCEPT7_I:.*]]
51+
// CHECK: [[__EXCEPT7_I]]:
52+
// CHECK-NEXT: [[TMP6:%.*]] = tail call i32 @llvm.eh.exceptioncode(token [[TMP5]])
53+
// CHECK-NEXT: br label %[[__TRY_CONT8_I]]
54+
// CHECK: [[__TRY_CONT8_I]]:
55+
// CHECK-NEXT: tail call void @"?Exit@@YAXXZ"() #[[ATTR7:[0-9]+]]
56+
// CHECK-NEXT: unreachable
57+
// CHECK: [[INVOKE_CONT2_I]]:
58+
// CHECK-NEXT: [[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0__I:%.*]] = load volatile i32, ptr [[ARGC_ADDR_I]], align 4, !tbaa [[INT_TBAA7]]
59+
// CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0__I]], 0
60+
// CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label %[[IF_END_I:.*]]
61+
// CHECK: [[IF_THEN_I]]:
62+
// CHECK-NEXT: [[TMP7:%.*]] = load volatile ptr, ptr @"?p@@3PECHEC", align 8, !tbaa [[INTPTR_TBAA11:![0-9]+]]
63+
// CHECK-NEXT: store volatile i32 0, ptr [[TMP7]], align 4, !tbaa [[INT_TBAA7]]
64+
// CHECK-NEXT: br label %[[IF_END_I]]
65+
// CHECK: [[IF_END_I]]:
66+
// CHECK-NEXT: [[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0_10_I:%.*]] = load volatile i32, ptr [[ARGC_ADDR_I]], align 4, !tbaa [[INT_TBAA7]]
67+
// CHECK-NEXT: store volatile i32 1, ptr [[CLEANUP_DEST_SLOT_I]], align 4
68+
// CHECK-NEXT: invoke void @llvm.seh.try.end()
69+
// CHECK-NEXT: to label %"?ExitOnThrow@@[email protected]" unwind label %[[CATCH_DISPATCH5_I]]
70+
// CHECK: "?ExitOnThrow@@[email protected]":
71+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[ARGC_ADDR_I]])
72+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[__EXCEPTION_CODE1_I]])
73+
// CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[CLEANUP_DEST_SLOT_I]])
74+
// CHECK-NEXT: [[CALL1:%.*]] = tail call noundef i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0_10_I]])
75+
// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_I_0_ARGC_ADDR_0_ARGC_ADDR_0_ARGC_ADDR_0_10_I]]
76+
// CHECK-NEXT: ret i32 [[ADD]]
77+
//
78+
int main(int argc, char**)
79+
{
80+
auto data = ExitOnThrow(argc);
81+
return data + AlwaysThrows(data);
82+
}
83+
//.
84+
// CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0}
85+
// CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0}
86+
// CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0}
87+
// CHECK: [[META10]] = !{!"Simple C++ TBAA"}
88+
// CHECK: [[INTPTR_TBAA11]] = !{[[META12:![0-9]+]], [[META12]], i64 0}
89+
// CHECK: [[META12]] = !{!"p1 int", [[META13:![0-9]+]], i64 0}
90+
// CHECK: [[META13]] = !{!"any pointer", [[META9]], i64 0}
91+
//.

0 commit comments

Comments
 (0)