1 // REQUIRES: webassembly-registered-target
2 // https://reviews.llvm.org/D79655 temporarily added a RUN line that was missing
3 // a -o flag and wrote to the source dir. The file it wrote was then interpreted
4 // as a test without RUN line, breaking bots. FIXME: Remove this rm line once
5 // it's been in the tree long enough to clean up everyone's build dirs.
6 // Removing this June 2020 should be fine.
7 // RUN: rm -f %S/wasm-eh.ll
8 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -fwasm-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
9 // RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -fwasm-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
10 
11 void may_throw();
12 void dont_throw() noexcept;
13 
14 struct Cleanup {
15   ~Cleanup() { dont_throw(); }
16 };
17 
18 // Multiple catch clauses w/o catch-all
19 void test0() {
20   try {
21     may_throw();
22   } catch (int) {
23     dont_throw();
24   } catch (double) {
25     dont_throw();
26   }
27 }
28 
29 // CHECK-LABEL: define void @_Z5test0v() {{.*}} personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*)
30 
31 // CHECK:   %[[INT_ALLOCA:.*]] = alloca i32
32 // CHECK:   invoke void @_Z9may_throwv()
33 // CHECK-NEXT:           to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]
34 
35 // CHECK: [[CATCHDISPATCH_BB]]:
36 // CHECK-NEXT:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
37 
38 // CHECK: [[CATCHSTART_BB]]:
39 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
40 // CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CATCHPAD]])
41 // CHECK-NEXT:   store i8* %[[EXN]], i8** %exn.slot
42 // CHECK-NEXT:   %[[SELECTOR:.*]] = call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]])
43 // CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #2
44 // CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
45 // CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]
46 
47 // CHECK: [[CATCH_INT_BB]]:
48 // CHECK-NEXT:   %[[EXN:.*]] = load i8*, i8** %exn.slot
49 // CHECK-NEXT:   %[[ADDR:.*]] = call i8* @__cxa_begin_catch(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
50 // CHECK-NEXT:   %[[ADDR_CAST:.*]] = bitcast i8* %[[ADDR]] to i32*
51 // CHECK-NEXT:   %[[INT_VAL:.*]] = load i32, i32* %[[ADDR_CAST]]
52 // CHECK-NEXT:   store i32 %[[INT_VAL]], i32* %[[INT_ALLOCA]]
53 // CHECK-NEXT:   call void @_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
54 // CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
55 // CHECK-NEXT:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]]
56 
57 // CHECK: [[CATCHRET_DEST_BB0]]:
58 // CHECK-NEXT:   br label %[[TRY_CONT_BB:.*]]
59 
60 // CHECK: [[CATCH_FALLTHROUGH_BB]]
61 // CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) #2
62 // CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
63 // CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]
64 
65 // CHECK: [[CATCH_FLOAT_BB]]:
66 // CHECK:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]
67 
68 // CHECK: [[CATCHRET_DEST_BB1]]:
69 // CHECK-NEXT:   br label %[[TRY_CONT_BB]]
70 
71 // CHECK: [[RETHROW_BB]]:
72 // CHECK-NEXT:   call void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
73 // CHECK-NEXT:   unreachable
74 
75 // Single catch-all
76 void test1() {
77   try {
78     may_throw();
79   } catch (...) {
80     dont_throw();
81   }
82 }
83 
84 // CATCH-LABEL: @_Z5test1v()
85 
86 // CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
87 
88 // CHECK: [[CATCHSTART_BB]]:
89 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
90 // CHECK:   br label %[[CATCH_ALL_BB:.*]]
91 
92 // CHECK: [[CATCH_ALL_BB]]:
93 // CHECK:   catchret from %[[CATCHPAD]] to label
94 
95 // Multiple catch clauses w/ catch-all
96 void test2() {
97   try {
98     may_throw();
99   } catch (int) {
100     dont_throw();
101   } catch (...) {
102     dont_throw();
103   }
104 }
105 
106 // CHECK-LABEL: @_Z5test2v()
107 
108 // CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
109 
110 // CHECK: [[CATCHSTART_BB]]:
111 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null]
112 // CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]
113 
114 // CHECK: [[CATCH_INT_BB]]:
115 // CHECK:   catchret from %[[CATCHPAD]] to label
116 
117 // CHECK: [[CATCH_ALL_BB]]:
118 // CHECK:   catchret from %[[CATCHPAD]] to label
119 
120 // Cleanup
121 void test3() {
122   Cleanup c;
123   may_throw();
124 }
125 
126 // CHECK-LABEL: @_Z5test3v()
127 
128 // CHECK:   invoke void @_Z9may_throwv()
129 // CHECK-NEXT:           to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]
130 
131 // CHECK: [[EHCLEANUP_BB]]:
132 // CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within none []
133 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
134 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller
135 
136 // Possibly throwing function call within a catch
137 void test4() {
138   try {
139     may_throw();
140   } catch (int) {
141     may_throw();
142   }
143 }
144 
145 // CHECK-LABEL: @_Z5test4v()
146 
147 // CHECK:   %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller
148 
149 // CHECK: [[CATCHSTART_BB]]:
150 // CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)]
151 
152 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
153 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]
154 
155 // CHECK: [[INVOKE_CONT_BB]]:
156 // CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
157 // CHECK-NEXT:   catchret from %[[CATCHPAD]] to label
158 
159 // CHECK: [[EHCLEANUP_BB]]:
160 // CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] []
161 // CHECK-NEXT:   call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
162 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller
163 
164 // Possibly throwing function call within a catch-all
165 void test5() {
166   try {
167     may_throw();
168   } catch (...) {
169     may_throw();
170   }
171 }
172 
173 // CHECK-LABEL: @_Z5test5v()
174 
175 // CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller
176 
177 // CHECK: [[CATCHSTART_BB]]:
178 // CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
179 
180 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
181 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]
182 
183 // CHECK: [[INVOKE_CONT_BB0]]:
184 // CHECK-NEXT:   call void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]
185 // CHECK-NEXT:   catchret from %[[CATCHPAD]] to label
186 
187 // CHECK: [[EHCLEANUP_BB]]:
188 // CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] []
189 // CHECK-NEXT:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ]
190 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]]
191 
192 // CHECK: [[INVOKE_CONT_BB1]]:
193 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind to caller
194 
195 // CHECK: [[TERMINATE_BB]]:
196 // CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []
197 // CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CLEANUPPAD1]])
198 // CHECK-NEXT:   call void @__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
199 // CHECK-NEXT:   unreachable
200 
201 // CHECK-LABEL: define {{.*}} void @__clang_call_terminate(i8* %0)
202 // CHECK-NEXT:   call i8* @__cxa_begin_catch(i8* %{{.*}})
203 // CHECK-NEXT:   call void @_ZSt9terminatev()
204 // CHECK-NEXT:   unreachable
205 
206 // Try-catch with cleanups
207 void test6() {
208   Cleanup c1;
209   try {
210     Cleanup c2;
211     may_throw();
212   } catch (int) {
213     Cleanup c3;
214     may_throw();
215   }
216 }
217 
218 // CHECK-LABEL: @_Z5test6v()
219 // CHECK:   invoke void @_Z9may_throwv()
220 // CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]
221 
222 // CHECK: [[EHCLEANUP_BB0]]:
223 // CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
224 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
225 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]
226 
227 // CHECK: [[CATCH_DISPATCH_BB]]:
228 // CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]
229 
230 // CHECK: [[CATCHSTART_BB]]:
231 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)]
232 // CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]
233 
234 // CHECK: [[CATCH_INT_BB]]:
235 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
236 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]
237 
238 // CHECK: [[INVOKE_CONT_BB]]:
239 // CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}
240 
241 // CHECK: [[RETHROW_BB]]:
242 // CHECK-NEXT:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
243 // CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]
244 
245 // CHECK: [[EHCLEANUP_BB2]]:
246 // CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
247 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
248 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]
249 
250 // CHECK: [[EHCLEANUP_BB3]]:
251 // CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
252 // CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]
253 
254 // CHECK: [[EHCLEANUP_BB1]]:
255 // CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []
256 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
257 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller
258 
259 // CHECK: [[UNREACHABLE_BB]]:
260 // CHECK-NEXT:   unreachable
261 
262 // Nested try-catches within a try with cleanups
263 void test7() {
264   Cleanup c1;
265   may_throw();
266   try {
267     Cleanup c2;
268     may_throw();
269     try {
270       Cleanup c3;
271       may_throw();
272     } catch (int) {
273       may_throw();
274     } catch (double) {
275       may_throw();
276     }
277   } catch (int) {
278     may_throw();
279   } catch (...) {
280     may_throw();
281   }
282 }
283 
284 // CHECK-LABEL: @_Z5test7v()
285 // CHECK:   invoke void @_Z9may_throwv()
286 
287 // CHECK:   invoke void @_Z9may_throwv()
288 
289 // CHECK:   invoke void @_Z9may_throwv()
290 
291 // CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
292 // CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label
293 
294 // CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none
295 
296 // CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
297 
298 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
299 
300 // CHECK:   catchret from %[[CATCHPAD0]] to label
301 
302 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
303 
304 // CHECK:   catchret from %[[CATCHPAD0]] to label
305 
306 // CHECK:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
307 
308 // CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
309 // CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label
310 
311 // CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
312 // CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label
313 
314 // CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []
315 // CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label
316 
317 // CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none
318 
319 // CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null]
320 
321 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
322 
323 // CHECK:   catchret from %[[CATCHPAD1]] to label
324 
325 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
326 
327 // CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]
328 
329 // CHECK:   catchret from %[[CATCHPAD1]] to label
330 
331 // CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
332 // CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]
333 
334 // CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label
335 
336 // CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
337 // CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label
338 
339 // CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []
340 // CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller
341 
342 // CHECK:   unreachable
343 
344 // CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
345 // CHECK:   call void @__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
346 // CHECK:   unreachable
347 
348 // Nested try-catches within a catch
349 void test8() {
350   try {
351     may_throw();
352   } catch (int) {
353     try {
354       may_throw();
355     } catch (int) {
356       may_throw();
357     }
358   }
359 }
360 
361 // CHECK-LABEL: @_Z5test8v()
362 // CHECK:   invoke void @_Z9may_throwv()
363 
364 // CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none
365 
366 // CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*)]
367 
368 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
369 
370 // CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]
371 
372 // CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*)]
373 
374 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
375 
376 // CHECK:   catchret from %[[CATCHPAD1]] to label
377 
378 // CHECK:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]
379 
380 // CHECK:   catchret from %[[CATCHPAD0]] to label
381 
382 // CHECK:   call void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
383 // CHECK:   unreachable
384 
385 // CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
386 // CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label
387 
388 // CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
389 // CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller
390 
391 // CHECK:   unreachable
392 
393 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -fwasm-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-DEFAULT
394 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -fwasm-exceptions -target-feature +exception-handling -Wwasm-exception-spec -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-ON
395 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -fwasm-exceptions -target-feature +exception-handling -Wno-wasm-exception-spec -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=WARNING-OFF
396 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=NOT-WASM-EH
397 
398 // Wasm EH ignores dynamic exception specifications with types at the moment.
399 // This is controlled by -Wwasm-exception-spec, which is on by default. This
400 // warning can be suppressed with -Wno-wasm-exception-spec. Checks if a warning
401 // message is correctly printed or not printed depending on the options.
402 void test9() throw(int) {
403 }
404 // WARNING-DEFAULT: warning: dynamic exception specifications with types are currently ignored in wasm
405 // WARNING-ON: warning: dynamic exception specifications with types are currently ignored in wasm
406 // WARNING-OFF-NOT: warning: dynamic exception specifications with types are currently ignored in wasm
407 // NOT-WASM-EH-NOT: warning: dynamic exception specifications with types are currently ignored in wasm
408 
409 // Wasm curremtly treats 'throw()' in the same way as 'noexept'. Check if the
410 // same warning message is printed as if when a 'noexcept' function throws.
411 void test10() throw() {
412   throw 3;
413 }
414 // WARNING-DEFAULT: warning: 'test10' has a non-throwing exception specification but can still throw
415 // WARNING-DEFAULT: function declared non-throwing here
416 
417 // Here we only check if the command enables wasm exception handling in the
418 // backend so that exception handling instructions can be generated in .s file.
419 
420 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -fwasm-exceptions -target-feature +exception-handling -S -o - -std=c++11 | FileCheck %s --check-prefix=ASSEMBLY
421 
422 // ASSEMBLY: try
423 // ASSEMBLY: catch
424 // ASSEMBLY: rethrow
425 // ASSEMBLY: end_try
426