Clang Project

clang_source_code/test/CodeGenCXX/exceptions-seh.cpp
1// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm \
2// RUN:         -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | \
3// RUN:         FileCheck %s --check-prefix=CHECK --check-prefix=CXXEH
4// RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s -triple=x86_64-windows-msvc -emit-llvm \
5// RUN:         -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
6// RUN:         FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
7
8extern "C" unsigned long _exception_code();
9extern "C" void might_throw();
10
11struct HasCleanup {
12  HasCleanup();
13  ~HasCleanup();
14  int padding;
15};
16
17extern "C" void use_cxx() {
18  HasCleanup x;
19  might_throw();
20}
21
22// Make sure we use __CxxFrameHandler3 for C++ EH.
23
24// CXXEH-LABEL: define dso_local void @use_cxx()
25// CXXEH-SAME:  personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
26// CXXEH: call %struct.HasCleanup* @"??0HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}})
27// CXXEH: invoke void @might_throw()
28// CXXEH:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
29//
30// CXXEH: [[cont]]
31// CXXEH: call void @"??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}})
32// CXXEH: ret void
33//
34// CXXEH: [[lpad]]
35// CXXEH: cleanuppad
36// CXXEH: call void @"??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}})
37// CXXEH: cleanupret
38
39// NOCXX-LABEL: define dso_local void @use_cxx()
40// NOCXX-NOT: invoke
41// NOCXX: call %struct.HasCleanup* @"??0HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}})
42// NOCXX-NOT: invoke
43// NOCXX: call void @might_throw()
44// NOCXX-NOT: invoke
45// NOCXX: call void @"??1HasCleanup@@QEAA@XZ"(%struct.HasCleanup* %{{.*}})
46// NOCXX-NOT: invoke
47// NOCXX: ret void
48
49extern "C" void use_seh() {
50  __try {
51    might_throw();
52  } __except(1) {
53  }
54}
55
56// Make sure we use __C_specific_handler for SEH.
57
58// CHECK-LABEL: define dso_local void @use_seh()
59// CHECK-SAME:  personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
60// CHECK: invoke void @might_throw() #[[NOINLINE:[0-9]+]]
61// CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
62//
63// CHECK: [[lpad]]
64// CHECK-NEXT: %[[switch:.*]] = catchswitch within none [label %[[cpad:.*]]] unwind to caller
65//
66// CHECK: [[cpad]]
67// CHECK-NEXT: catchpad within %[[switch]]
68// CHECK: catchret {{.*}} label %[[except:[^ ]*]]
69//
70// CHECK: [[except]]
71// CHECK: br label %[[ret:[^ ]*]]
72//
73// CHECK: [[ret]]
74// CHECK: ret void
75//
76// CHECK: [[cont]]
77// CHECK: br label %[[ret]]
78
79extern "C" void nested_finally() {
80  __try {
81    might_throw();
82  } __finally {
83    __try {
84      might_throw();
85    } __finally {
86    }
87  }
88}
89
90// CHECK-LABEL: define dso_local void @nested_finally() #{{[0-9]+}}
91// CHECK-SAME:  personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
92// CHECK: invoke void @might_throw()
93// CHECK: call void @"?fin$0@0@nested_finally@@"(i8 1, i8* {{.*}})
94
95// CHECK-LABEL: define internal void @"?fin$0@0@nested_finally@@"
96// CHECK-SAME:  personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
97// CHECK: invoke void @might_throw()
98// CHECK: call void @"?fin$1@0@nested_finally@@"(i8 1, i8* {{.*}})
99
100void use_seh_in_lambda() {
101  ([]() {
102    __try {
103      might_throw();
104    } __except(1) {
105    }
106  })();
107  HasCleanup x;
108  might_throw();
109}
110
111// CXXEH-LABEL: define dso_local void @"?use_seh_in_lambda@@YAXXZ"()
112// CXXEH-SAME:  personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
113// CXXEH: cleanuppad
114
115// NOCXX-LABEL: define dso_local void @"?use_seh_in_lambda@@YAXXZ"()
116// NOCXX-NOT: invoke
117// NOCXX: ret void
118
119// CHECK-LABEL: define internal void @"??R<lambda_0>@?0??use_seh_in_lambda@@YAXXZ@QEBA@XZ"(%class.anon* %this)
120// CXXEH-SAME:  personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
121// CHECK: invoke void @might_throw() #[[NOINLINE]]
122// CHECK: catchpad
123
124static int my_unique_global;
125
126extern "C" inline void use_seh_in_inline_func() {
127  __try {
128    might_throw();
129  } __except(_exception_code() == 424242) {
130  }
131  __try {
132    might_throw();
133  } __finally {
134    my_unique_global = 1234;
135  }
136}
137
138void use_inline() {
139  use_seh_in_inline_func();
140}
141
142// CHECK-LABEL: define linkonce_odr dso_local void @use_seh_in_inline_func() #{{[0-9]+}}
143// CHECK-SAME:  personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
144// CHECK: invoke void @might_throw()
145//
146// CHECK: catchpad {{.*}} [i8* bitcast (i32 (i8*, i8*)* @"?filt$0@0@use_seh_in_inline_func@@" to i8*)]
147//
148// CHECK: invoke void @might_throw()
149//
150// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
151// CHECK: call void @"?fin$0@0@use_seh_in_inline_func@@"(i8 0, i8* %[[fp]])
152// CHECK: ret void
153//
154// CHECK: cleanuppad
155// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
156// CHECK: call void @"?fin$0@0@use_seh_in_inline_func@@"(i8 1, i8* %[[fp]])
157
158// CHECK-LABEL: define internal i32 @"?filt$0@0@use_seh_in_inline_func@@"(i8* %exception_pointers, i8* %frame_pointer) #{{[0-9]+}}
159// CHECK: icmp eq i32 %{{.*}}, 424242
160// CHECK: zext i1 %{{.*}} to i32
161// CHECK: ret i32
162
163// CHECK-LABEL: define internal void @"?fin$0@0@use_seh_in_inline_func@@"(i8 %abnormal_termination, i8* %frame_pointer) #{{[0-9]+}}
164// CHECK: store i32 1234, i32* @my_unique_global
165
166// CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
167