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