1 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
2 // RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
3 
4 void may_throw();
5 void dont_throw() noexcept;
6 
7 struct Cleanup {
8   ~Cleanup() { dont_throw(); }
9 };
10 
11 // Multiple catch clauses w/o catch-all
12 void test0() {
13   try {
14     may_throw();
15   } catch (int) {
16     dont_throw();
17   } catch (double) {
18     dont_throw();
19   }
20 }
21 
22 // CHECK-LABEL: define void @_Z5test0v() {{.*}} personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*)
23 
24 // CHECK:   %[[INT_ALLOCA:.*]] = alloca i32
25 // CHECK:   invoke void @_Z9may_throwv()
26 // CHECK-NEXT:           to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]
27 
28 // CHECK: [[CATCHDISPATCH_BB]]:
29 // CHECK-NEXT:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
30 
31 // CHECK: [[CATCHSTART_BB]]:
32 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
33 // CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CATCHPAD]])
34 // CHECK-NEXT:   store i8* %[[EXN]], i8** %exn.slot
35 // CHECK-NEXT:   %[[SELECTOR:.*]] = call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]])
36 // CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #2
37 // CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
38 // CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]
39 
40 // CHECK: [[CATCH_INT_BB]]:
41 // CHECK-NEXT:   %[[EXN:.*]] = load i8*, i8** %exn.slot
42 // CHECK-NEXT:   %[[ADDR:.*]] = call i8* @__cxa_begin_catch(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
43 // CHECK-NEXT:   %[[ADDR_CAST:.*]] = bitcast i8* %[[ADDR]] to i32*
44 // CHECK-NEXT:   %[[INT_VAL:.*]] = load i32, i32* %[[ADDR_CAST]]
45 // CHECK-NEXT:   store i32 %[[INT_VAL]], i32* %[[INT_ALLOCA]]
46 // CHECK-NEXT:   call void @_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
47 // CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
48 // CHECK-NEXT:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]]
49 
50 // CHECK: [[CATCHRET_DEST_BB0]]:
51 // CHECK-NEXT:   br label %[[TRY_CONT_BB:.*]]
52 
53 // CHECK: [[CATCH_FALLTHROUGH_BB]]
54 // CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) #2
55 // CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
56 // CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]
57 
58 // CHECK: [[CATCH_FLOAT_BB]]:
59 // CHECK:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]
60 
61 // CHECK: [[CATCHRET_DEST_BB1]]:
62 // CHECK-NEXT:   br label %[[TRY_CONT_BB]]
63 
64 // CHECK: [[RETHROW_BB]]:
65 // CHECK-NEXT:   call void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
66 // CHECK-NEXT:   unreachable
67 
68 // Single catch-all
69 void test1() {
70   try {
71     may_throw();
72   } catch (...) {
73     dont_throw();
74   }
75 }
76 
77 // CATCH-LABEL: @_Z5test1v()
78 
79 // CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
80 
81 // CHECK: [[CATCHSTART_BB]]:
82 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
83 // CHECK:   br label %[[CATCH_ALL_BB:.*]]
84 
85 // CHECK: [[CATCH_ALL_BB]]:
86 // CHECK:   catchret from %[[CATCHPAD]] to label
87 
88 // Multiple catch clauses w/ catch-all
89 void test2() {
90   try {
91     may_throw();
92   } catch (int) {
93     dont_throw();
94   } catch (...) {
95     dont_throw();
96   }
97 }
98 
99 // CHECK-LABEL: @_Z5test2v()
100 
101 // CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
102 
103 // CHECK: [[CATCHSTART_BB]]:
104 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null]
105 // CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]
106 
107 // CHECK: [[CATCH_INT_BB]]:
108 // CHECK:   catchret from %[[CATCHPAD]] to label
109 
110 // CHECK: [[CATCH_ALL_BB]]:
111 // CHECK:   catchret from %[[CATCHPAD]] to label
112 
113 // Cleanup
114 void test3() {
115   Cleanup c;
116   may_throw();
117 }
118 
119 // CHECK-LABEL: @_Z5test3v()
120 
121 // CHECK:   invoke void @_Z9may_throwv()
122 // CHECK-NEXT:           to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]
123 
124 // CHECK: [[EHCLEANUP_BB]]:
125 // CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within none []
126 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
127 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller
128 
129 // Possibly throwing function call within a catch
130 void test4() {
131   try {
132     may_throw();
133   } catch (int) {
134     may_throw();
135   }
136 }
137 
138 // CHECK-LABEL: @_Z5test4v()
139 
140 // CHECK:   %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller
141 
142 // CHECK: [[CATCHSTART_BB]]:
143 // CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)]
144 
145 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
146 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]
147 
148 // CHECK: [[INVOKE_CONT_BB]]:
149 // CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
150 // CHECK-NEXT:   catchret from %[[CATCHPAD]] to label
151 
152 // CHECK: [[EHCLEANUP_BB]]:
153 // CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] []
154 // CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
155 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller
156 
157 // Possibly throwing function call within a catch-all
158 void test5() {
159   try {
160     may_throw();
161   } catch (...) {
162     may_throw();
163   }
164 }
165 
166 // CHECK-LABEL: @_Z5test5v()
167 
168 // CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller
169 
170 // CHECK: [[CATCHSTART_BB]]:
171 // CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
172 
173 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
174 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]
175 
176 // CHECK: [[INVOKE_CONT_BB0]]:
177 // CHECK-NEXT:   call void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]
178 // CHECK-NEXT:   catchret from %[[CATCHPAD]] to label
179 
180 // CHECK: [[EHCLEANUP_BB]]:
181 // CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] []
182 // CHECK-NEXT:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ]
183 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]]
184 
185 // CHECK: [[INVOKE_CONT_BB1]]:
186 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind to caller
187 
188 // CHECK: [[TERMINATE_BB]]:
189 // CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []
190 // CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CLEANUPPAD1]])
191 // CHECK-NEXT:   call void @__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
192 // CHECK-NEXT:   unreachable
193 
194 // CHECK-LABEL: define {{.*}} void @__clang_call_terminate(i8* %0)
195 // CHECK-NEXT:   call i8* @__cxa_begin_catch(i8* %{{.*}})
196 // CHECK-NEXT:   call void @_ZSt9terminatev()
197 // CHECK-NEXT:   unreachable
198 
199 // Try-catch with cleanups
200 void test6() {
201   Cleanup c1;
202   try {
203     Cleanup c2;
204     may_throw();
205   } catch (int) {
206     Cleanup c3;
207     may_throw();
208   }
209 }
210 
211 // CHECK-LABEL: @_Z5test6v()
212 // CHECK:   invoke void @_Z9may_throwv()
213 // CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]
214 
215 // CHECK: [[EHCLEANUP_BB0]]:
216 // CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
217 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
218 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]
219 
220 // CHECK: [[CATCH_DISPATCH_BB]]:
221 // CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]
222 
223 // CHECK: [[CATCHSTART_BB]]:
224 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)]
225 // CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]
226 
227 // CHECK: [[CATCH_INT_BB]]:
228 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
229 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]
230 
231 // CHECK: [[INVOKE_CONT_BB]]:
232 // CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}
233 
234 // CHECK: [[RETHROW_BB]]:
235 // CHECK-NEXT:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
236 // CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]
237 
238 // CHECK: [[EHCLEANUP_BB2]]:
239 // CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
240 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
241 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]
242 
243 // CHECK: [[EHCLEANUP_BB3]]:
244 // CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
245 // CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]
246 
247 // CHECK: [[EHCLEANUP_BB1]]:
248 // CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []
249 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
250 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller
251 
252 // CHECK: [[UNREACHABLE_BB]]:
253 // CHECK-NEXT:   unreachable
254 
255 // Nested try-catches within a try with cleanups
256 void test7() {
257   Cleanup c1;
258   may_throw();
259   try {
260     Cleanup c2;
261     may_throw();
262     try {
263       Cleanup c3;
264       may_throw();
265     } catch (int) {
266       may_throw();
267     } catch (double) {
268       may_throw();
269     }
270   } catch (int) {
271     may_throw();
272   } catch (...) {
273     may_throw();
274   }
275 }
276 
277 // CHECK-LABEL: @_Z5test7v()
278 // CHECK:   invoke void @_Z9may_throwv()
279 
280 // CHECK:   invoke void @_Z9may_throwv()
281 
282 // CHECK:   invoke void @_Z9may_throwv()
283 
284 // CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
285 // CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label
286 
287 // CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none
288 
289 // CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
290 
291 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
292 
293 // CHECK:   catchret from %[[CATCHPAD0]] to label
294 
295 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
296 
297 // CHECK:   catchret from %[[CATCHPAD0]] to label
298 
299 // CHECK:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
300 
301 // CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
302 // CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label
303 
304 // CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
305 // CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label
306 
307 // CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []
308 // CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label
309 
310 // CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none
311 
312 // CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null]
313 
314 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
315 
316 // CHECK:   catchret from %[[CATCHPAD1]] to label
317 
318 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
319 
320 // CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]
321 
322 // CHECK:   catchret from %[[CATCHPAD1]] to label
323 
324 // CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
325 // CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]
326 
327 // CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label
328 
329 // CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
330 // CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label
331 
332 // CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []
333 // CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller
334 
335 // CHECK:   unreachable
336 
337 // CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
338 // CHECK:   call void @__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
339 // CHECK:   unreachable
340 
341 // Nested try-catches within a catch
342 void test8() {
343   try {
344     may_throw();
345   } catch (int) {
346     try {
347       may_throw();
348     } catch (int) {
349       may_throw();
350     }
351   }
352 }
353 
354 // CHECK-LABEL: @_Z5test8v()
355 // CHECK:   invoke void @_Z9may_throwv()
356 
357 // CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none
358 
359 // CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*)]
360 
361 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
362 
363 // CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]
364 
365 // CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*)]
366 
367 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
368 
369 // CHECK:   catchret from %[[CATCHPAD1]] to label
370 
371 // CHECK:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]
372 
373 // CHECK:   catchret from %[[CATCHPAD0]] to label
374 
375 // CHECK:   call void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
376 // CHECK:   unreachable
377 
378 // CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
379 // CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label
380 
381 // CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
382 // CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller
383 
384 // CHECK:   unreachable
385