1 // REQUIRES: webassembly-registered-target
2 // 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
3 // 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
4 
5 void may_throw();
6 void dont_throw() noexcept;
7 
8 struct Cleanup {
9   ~Cleanup() { dont_throw(); }
10 };
11 
12 // Multiple catch clauses w/o catch-all
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.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
67 // CHECK-NEXT:   unreachable
68 
69 // Single catch-all
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
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
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 %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
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
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:   %[[EXN:.*]] = call i8* @llvm.wasm.get.exception(token %[[CLEANUPPAD1]])
192 // CHECK-NEXT:   call void @__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
193 // CHECK-NEXT:   unreachable
194 
195 // CHECK-LABEL: define {{.*}} void @__clang_call_terminate(i8* %0)
196 // CHECK-NEXT:   call i8* @__cxa_begin_catch(i8* %{{.*}})
197 // CHECK-NEXT:   call void @_ZSt9terminatev()
198 // CHECK-NEXT:   unreachable
199 
200 // Try-catch with cleanups
201 void test6() {
202   Cleanup c1;
203   try {
204     Cleanup c2;
205     may_throw();
206   } catch (int) {
207     Cleanup c3;
208     may_throw();
209   }
210 }
211 
212 // CHECK-LABEL: @_Z5test6v()
213 // CHECK:   invoke void @_Z9may_throwv()
214 // CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]
215 
216 // CHECK: [[EHCLEANUP_BB0]]:
217 // CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
218 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
219 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]
220 
221 // CHECK: [[CATCH_DISPATCH_BB]]:
222 // CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]
223 
224 // CHECK: [[CATCHSTART_BB]]:
225 // CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @_ZTIi to i8*)]
226 // CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]
227 
228 // CHECK: [[CATCH_INT_BB]]:
229 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
230 // CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]
231 
232 // CHECK: [[INVOKE_CONT_BB]]:
233 // CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}
234 
235 // CHECK: [[RETHROW_BB]]:
236 // CHECK-NEXT:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
237 // CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]
238 
239 // CHECK: [[EHCLEANUP_BB2]]:
240 // CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
241 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
242 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]
243 
244 // CHECK: [[EHCLEANUP_BB3]]:
245 // CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
246 // CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]
247 
248 // CHECK: [[EHCLEANUP_BB1]]:
249 // CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []
250 // CHECK-NEXT:   call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
251 // CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller
252 
253 // CHECK: [[UNREACHABLE_BB]]:
254 // CHECK-NEXT:   unreachable
255 
256 // Nested try-catches within a try with cleanups
257 void test7() {
258   Cleanup c1;
259   may_throw();
260   try {
261     Cleanup c2;
262     may_throw();
263     try {
264       Cleanup c3;
265       may_throw();
266     } catch (int) {
267       may_throw();
268     } catch (double) {
269       may_throw();
270     }
271   } catch (int) {
272     may_throw();
273   } catch (...) {
274     may_throw();
275   }
276 }
277 
278 // CHECK-LABEL: @_Z5test7v()
279 // CHECK:   invoke void @_Z9may_throwv()
280 
281 // CHECK:   invoke void @_Z9may_throwv()
282 
283 // CHECK:   invoke void @_Z9may_throwv()
284 
285 // CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
286 // CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label
287 
288 // CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none
289 
290 // CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
291 
292 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
293 
294 // CHECK:   catchret from %[[CATCHPAD0]] to label
295 
296 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
297 
298 // CHECK:   catchret from %[[CATCHPAD0]] to label
299 
300 // CHECK:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
301 
302 // CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
303 // CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label
304 
305 // CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
306 // CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label
307 
308 // CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []
309 // CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label
310 
311 // CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none
312 
313 // CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*), i8* null]
314 
315 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
316 
317 // CHECK:   catchret from %[[CATCHPAD1]] to label
318 
319 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
320 
321 // CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]
322 
323 // CHECK:   catchret from %[[CATCHPAD1]] to label
324 
325 // CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
326 // CHECK:   invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]
327 
328 // CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label
329 
330 // CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
331 // CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label
332 
333 // CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []
334 // CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller
335 
336 // CHECK:   unreachable
337 
338 // CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
339 // CHECK:   call void @__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
340 // CHECK:   unreachable
341 
342 // Nested try-catches within a catch
343 void test8() {
344   try {
345     may_throw();
346   } catch (int) {
347     try {
348       may_throw();
349     } catch (int) {
350       may_throw();
351     }
352   }
353 }
354 
355 // CHECK-LABEL: @_Z5test8v()
356 // CHECK:   invoke void @_Z9may_throwv()
357 
358 // CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none
359 
360 // CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @_ZTIi to i8*)]
361 
362 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
363 
364 // CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]
365 
366 // CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @_ZTIi to i8*)]
367 
368 // CHECK:   invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
369 
370 // CHECK:   catchret from %[[CATCHPAD1]] to label
371 
372 // CHECK:   invoke void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]
373 
374 // CHECK:   catchret from %[[CATCHPAD0]] to label
375 
376 // CHECK:   call void @llvm.wasm.rethrow.in.catch() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
377 // CHECK:   unreachable
378 
379 // CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
380 // CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label
381 
382 // CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
383 // CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller
384 
385 // CHECK:   unreachable
386 
387 // 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
388 // 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
389 // 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
390 // 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
391 
392 // Wasm EH ignores dynamic exception specifications with types at the moment.
393 // This is controlled by -Wwasm-exception-spec, which is on by default. This
394 // warning can be suppressed with -Wno-wasm-exception-spec. Checks if a warning
395 // message is correctly printed or not printed depending on the options.
396 void test9() throw(int) {
397 }
398 // WARNING-DEFAULT: warning: dynamic exception specifications with types are currently ignored in wasm
399 // WARNING-ON: warning: dynamic exception specifications with types are currently ignored in wasm
400 // WARNING-OFF-NOT: warning: dynamic exception specifications with types are currently ignored in wasm
401 // NOT-WASM-EH-NOT: warning: dynamic exception specifications with types are currently ignored in wasm
402 
403 // Wasm curremtly treats 'throw()' in the same way as 'noexept'. Check if the
404 // same warning message is printed as if when a 'noexcept' function throws.
405 void test10() throw() {
406   throw 3;
407 }
408 // WARNING-DEFAULT: warning: 'test10' has a non-throwing exception specification but can still throw
409 // WARNING-DEFAULT: function declared non-throwing here
410 
411 // Here we only check if the command enables wasm exception handling in the
412 // backend so that exception handling instructions can be generated in .s file.
413 
414 // 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
415 
416 // ASSEMBLY: try
417 // ASSEMBLY: catch
418 // ASSEMBLY: rethrow
419 // ASSEMBLY: end_try
420