-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[WinEH] Fix try scopes leaking to caller on inline #167176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 | ||
| // 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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We generally prefer clang tests to run with optimizations disabled: it makes it easier to see the correspondence between what we're testing and what's actually getting generated, and it makes the tests less sensitive to optimizer changes. (There's a minor downside that it doesn't always capture the end-to-end result, but usually a set of clang tests plus a set of LLVM optimizer tests is sufficient.) |
||
| // Check that the try scope of ExitOnThrow is terminated upon inlining into main. | ||
| int AlwaysThrows(int); | ||
| [[noreturn]] void Exit(); | ||
|
|
||
| int ExitOnThrow(int argc) noexcept | ||
| { | ||
| try { | ||
| if (!argc) { throw -1; } | ||
| return argc; | ||
| } catch (...) { | ||
| } | ||
|
|
||
| Exit(); | ||
| return 0; | ||
| } | ||
|
|
||
| // CHECK-LABEL: define dso_local noundef i32 @main( | ||
| // CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] personality ptr @__CxxFrameHandler3 { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[TMP_I:%.*]] = alloca i32, align 4 | ||
| // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TMP_I]]) | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.begin() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT_I:.*]] unwind label %[[CATCH_DISPATCH_I:.*]] | ||
| // CHECK: [[INVOKE_CONT_I]]: | ||
| // CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC]], 0 | ||
| // CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label %[[IF_END_I:.*]] | ||
| // CHECK: [[IF_THEN_I]]: | ||
| // CHECK-NEXT: store i32 -1, ptr [[TMP_I]], align 4, !tbaa [[INT_TBAA7:![0-9]+]] | ||
| // CHECK-NEXT: invoke void @_CxxThrowException(ptr nonnull [[TMP_I]], ptr nonnull @_TI1H) #[[ATTR6:[0-9]+]] | ||
| // CHECK-NEXT: to label %[[UNREACHABLE_I:.*]] unwind label %[[CATCH_DISPATCH_I]] | ||
| // CHECK: [[CATCH_DISPATCH_I]]: | ||
| // CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %[[CATCH_I:.*]]] unwind to caller | ||
| // CHECK: [[CATCH_I]]: | ||
| // CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 0, ptr null] | ||
| // CHECK-NEXT: catchret from [[TMP2]] to label %[[TRY_CONT_I:.*]] | ||
| // CHECK: [[TRY_CONT_I]]: | ||
| // CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR7:[0-9]+]] | ||
| // CHECK-NEXT: unreachable | ||
| // CHECK: [[IF_END_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.end() | ||
| // CHECK-NEXT: to label %"?ExitOnThrow@@[email protected]" unwind label %[[CATCH_DISPATCH_I]] | ||
| // CHECK: [[UNREACHABLE_I]]: | ||
| // CHECK-NEXT: unreachable | ||
| // CHECK: "?ExitOnThrow@@[email protected]": | ||
| // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TMP_I]]) | ||
| // CHECK-NEXT: [[CALL1:%.*]] = tail call noundef i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC]]) | ||
| // CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC]] | ||
| // CHECK-NEXT: ret i32 [[ADD]] | ||
| // | ||
| int main(int argc, char**) | ||
| { | ||
| auto data = ExitOnThrow(argc); | ||
| return data + AlwaysThrows(data); | ||
| } | ||
| //. | ||
| // CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0} | ||
| // CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0} | ||
| // CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0} | ||
| // CHECK: [[META10]] = !{!"Simple C++ TBAA"} | ||
| //. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 | ||
| // 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 | ||
| // Check that only the outermost try scope containing a return statement is terminated upon inlining into main. | ||
| void DoSth(); | ||
| int AlwaysThrows(int); | ||
| [[noreturn]] void Exit(); | ||
|
|
||
| int ExitOnThrow(int argc) noexcept | ||
| { | ||
| try { | ||
| try { | ||
| DoSth(); | ||
| } catch(...) {} | ||
| } catch(...) {} | ||
|
|
||
| try { | ||
| try { | ||
| if (!argc) { throw -1; } | ||
| return argc; | ||
| } catch (...) {} | ||
| } catch (...) {} | ||
|
|
||
| Exit(); | ||
| return 0; | ||
| } | ||
|
|
||
| // CHECK-LABEL: define dso_local noundef i32 @main( | ||
| // CHECK-SAME: i32 noundef [[ARGC:%.*]], ptr noundef readnone captures(none) [[TMP0:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] personality ptr @__CxxFrameHandler3 { | ||
| // CHECK-NEXT: [[ENTRY:.*:]] | ||
| // CHECK-NEXT: [[TMP_I:%.*]] = alloca i32, align 4 | ||
| // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[TMP_I]]) | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.begin() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT_I:.*]] unwind label %[[CATCH_DISPATCH6_I:.*]] | ||
| // CHECK: [[INVOKE_CONT_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.begin() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT1_I:.*]] unwind label %[[CATCH_DISPATCH_I:.*]] | ||
| // CHECK: [[INVOKE_CONT1_I]]: | ||
| // CHECK-NEXT: invoke void @"?DoSth@@YAXXZ"() | ||
| // CHECK-NEXT: to label %[[TRY_CONT_I:.*]] unwind label %[[CATCH_DISPATCH_I]] | ||
| // CHECK: [[CATCH_DISPATCH_I]]: | ||
| // CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %[[CATCH_I:.*]]] unwind label %[[CATCH_DISPATCH6_I]] | ||
| // CHECK: [[CATCH_I]]: | ||
| // 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_CONT3_I:.*]] unwind label %[[CATCH_DISPATCH6_I]] | ||
| // CHECK: [[INVOKE_CONT3_I]]: | ||
| // CHECK-NEXT: catchret from [[TMP2]] to label %[[TRY_CONT_I]] | ||
| // CHECK: [[TRY_CONT_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.scope.end() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT4_I:.*]] unwind label %[[CATCH_DISPATCH6_I]] | ||
| // CHECK: [[CATCH_DISPATCH6_I]]: | ||
| // CHECK-NEXT: [[TMP3:%.*]] = catchswitch within none [label %[[CATCH7_I:.*]]] unwind to caller | ||
| // CHECK: [[CATCH7_I]]: | ||
| // CHECK-NEXT: [[TMP4:%.*]] = catchpad within [[TMP3]] [ptr null, i32 0, ptr null] | ||
| // CHECK-NEXT: catchret from [[TMP4]] to label %[[TRY_CONT9_I:.*]] | ||
| // CHECK: [[TRY_CONT9_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.begin() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT10_I:.*]] unwind label %[[CATCH_DISPATCH19_I:.*]] | ||
| // CHECK: [[INVOKE_CONT10_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.begin() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT11_I:.*]] unwind label %[[CATCH_DISPATCH12_I:.*]] | ||
| // CHECK: [[INVOKE_CONT11_I]]: | ||
| // CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[ARGC]], 0 | ||
| // CHECK-NEXT: br i1 [[TOBOOL_NOT_I]], label %[[IF_THEN_I:.*]], label %[[CLEANUP_I:.*]] | ||
| // CHECK: [[IF_THEN_I]]: | ||
| // CHECK-NEXT: store i32 -1, ptr [[TMP_I]], align 4, !tbaa [[INT_TBAA7:![0-9]+]] | ||
| // CHECK-NEXT: invoke void @_CxxThrowException(ptr nonnull [[TMP_I]], ptr nonnull @_TI1H) #[[ATTR7:[0-9]+]] | ||
| // CHECK-NEXT: to label %[[UNREACHABLE_I:.*]] unwind label %[[CATCH_DISPATCH12_I]] | ||
| // CHECK: [[CATCH_DISPATCH12_I]]: | ||
| // CHECK-NEXT: [[TMP5:%.*]] = catchswitch within none [label %[[CATCH13_I:.*]]] unwind label %[[CATCH_DISPATCH19_I]] | ||
| // CHECK: [[CATCH13_I]]: | ||
| // CHECK-NEXT: [[TMP6:%.*]] = catchpad within [[TMP5]] [ptr null, i32 0, ptr null] | ||
| // CHECK-NEXT: invoke void @llvm.seh.scope.end() [ "funclet"(token [[TMP6]]) ] | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT14_I:.*]] unwind label %[[CATCH_DISPATCH19_I]] | ||
| // CHECK: [[INVOKE_CONT14_I]]: | ||
| // CHECK-NEXT: catchret from [[TMP6]] to label %[[CLEANUP_I]] | ||
| // CHECK: [[CLEANUP_I]]: | ||
| // CHECK-NEXT: [[COND_I:%.*]] = phi i1 [ true, %[[INVOKE_CONT14_I]] ], [ false, %[[INVOKE_CONT11_I]] ] | ||
| // CHECK-NEXT: invoke void @llvm.seh.scope.end() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT17_I:.*]] unwind label %[[CATCH_DISPATCH19_I]] | ||
| // CHECK: [[CATCH_DISPATCH19_I]]: | ||
| // CHECK-NEXT: [[TMP7:%.*]] = catchswitch within none [label %[[CATCH20_I:.*]]] unwind to caller | ||
| // CHECK: [[CATCH20_I]]: | ||
| // CHECK-NEXT: [[TMP8:%.*]] = catchpad within [[TMP7]] [ptr null, i32 0, ptr null] | ||
| // CHECK-NEXT: catchret from [[TMP8]] to label %[[TRY_CONT22_I:.*]] | ||
| // CHECK: [[TRY_CONT22_I]]: | ||
| // CHECK-NEXT: call void @"?Exit@@YAXXZ"() #[[ATTR8:[0-9]+]] | ||
| // CHECK-NEXT: unreachable | ||
| // CHECK: [[INVOKE_CONT17_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.end() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT18_I:.*]] unwind label %[[CATCH_DISPATCH12_I]] | ||
| // CHECK: [[INVOKE_CONT18_I]]: | ||
| // CHECK-NEXT: br i1 [[COND_I]], label %[[TRY_CONT22_I]], label %[[CLEANUP23_I:.*]] | ||
| // CHECK: [[INVOKE_CONT4_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.end() | ||
| // CHECK-NEXT: to label %[[TRY_CONT9_I]] unwind label %[[CATCH_DISPATCH_I]] | ||
| // CHECK: [[CLEANUP23_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.end() | ||
| // CHECK-NEXT: to label %[[INVOKE_CONT24_I:.*]] unwind label %[[CATCH_DISPATCH19_I]] | ||
| // CHECK: [[INVOKE_CONT24_I]]: | ||
| // CHECK-NEXT: invoke void @llvm.seh.try.end() | ||
| // CHECK-NEXT: to label %"?ExitOnThrow@@[email protected]" unwind label %[[CATCH_DISPATCH6_I]] | ||
| // CHECK: [[UNREACHABLE_I]]: | ||
| // CHECK-NEXT: unreachable | ||
| // CHECK: "?ExitOnThrow@@[email protected]": | ||
| // CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[TMP_I]]) | ||
| // CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @"?AlwaysThrows@@YAHH@Z"(i32 noundef [[ARGC]]) | ||
| // CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[ARGC]] | ||
| // CHECK-NEXT: ret i32 [[ADD]] | ||
| // | ||
| int main(int argc, char**) | ||
| { | ||
| auto data = ExitOnThrow(argc); | ||
| return data + AlwaysThrows(data); | ||
| } | ||
| //. | ||
| // CHECK: [[INT_TBAA7]] = !{[[META8:![0-9]+]], [[META8]], i64 0} | ||
| // CHECK: [[META8]] = !{!"int", [[META9:![0-9]+]], i64 0} | ||
| // CHECK: [[META9]] = !{!"omnipotent char", [[META10:![0-9]+]], i64 0} | ||
| // CHECK: [[META10]] = !{!"Simple C++ TBAA"} | ||
| //. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not worth the extra code here to try to reserve the exact amount in the array.