1 // REQUIRES: webassembly-registered-target
2 // RUN: %clang_cc1 %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 %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
6 void dont_throw() noexcept
;
9 ~Cleanup() { dont_throw(); }
12 // Multiple catch clauses w/o catch-all
23 // CHECK-LABEL: define void @_Z5test0v() {{.*}} personality ptr @__gxx_wasm_personality_v0
25 // CHECK: %[[INT_ALLOCA:.*]] = alloca i32
26 // CHECK: invoke void @_Z9may_throwv()
27 // CHECK-NEXT: to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]
29 // CHECK: [[CATCHDISPATCH_BB]]:
30 // CHECK-NEXT: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
32 // CHECK: [[CATCHSTART_BB]]:
33 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi, ptr @_ZTId]
34 // CHECK-NEXT: %[[EXN:.*]] = call ptr @llvm.wasm.get.exception(token %[[CATCHPAD]])
35 // CHECK-NEXT: store ptr %[[EXN]], ptr %exn.slot
36 // CHECK-NEXT: %[[SELECTOR:.*]] = call i32 @llvm.wasm.get.ehselector(token %[[CATCHPAD]])
37 // CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #8
38 // CHECK-NEXT: %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
39 // CHECK-NEXT: br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]
41 // CHECK: [[CATCH_INT_BB]]:
42 // CHECK-NEXT: %[[EXN:.*]] = load ptr, ptr %exn.slot
43 // CHECK-NEXT: %[[ADDR:.*]] = call ptr @__cxa_begin_catch(ptr %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
44 // CHECK-NEXT: %[[INT_VAL:.*]] = load i32, ptr %[[ADDR]]
45 // CHECK-NEXT: store i32 %[[INT_VAL]], ptr %[[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:.*]]
50 // CHECK: [[CATCHRET_DEST_BB0]]:
51 // CHECK-NEXT: br label %[[TRY_CONT_BB:.*]]
53 // CHECK: [[CATCH_FALLTHROUGH_BB]]
54 // CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTId) #8
55 // CHECK-NEXT: %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
56 // CHECK-NEXT: br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]
58 // CHECK: [[CATCH_FLOAT_BB]]:
59 // CHECK: catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]
61 // CHECK: [[CATCHRET_DEST_BB1]]:
62 // CHECK-NEXT: br label %[[TRY_CONT_BB]]
64 // CHECK: [[RETHROW_BB]]:
65 // CHECK-NEXT: call void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
66 // CHECK-NEXT: unreachable
77 // CATCH-LABEL: @_Z5test1v()
79 // CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
81 // CHECK: [[CATCHSTART_BB]]:
82 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr null]
83 // CHECK: br label %[[CATCH_ALL_BB:.*]]
85 // CHECK: [[CATCH_ALL_BB]]:
86 // CHECK: catchret from %[[CATCHPAD]] to label
88 // Multiple catch clauses w/ catch-all
99 // CHECK-LABEL: @_Z5test2v()
101 // CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller
103 // CHECK: [[CATCHSTART_BB]]:
104 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi, ptr null]
105 // CHECK: br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]
107 // CHECK: [[CATCH_INT_BB]]:
108 // CHECK: catchret from %[[CATCHPAD]] to label
110 // CHECK: [[CATCH_ALL_BB]]:
111 // CHECK: catchret from %[[CATCHPAD]] to label
119 // CHECK-LABEL: @_Z5test3v()
121 // CHECK: invoke void @_Z9may_throwv()
122 // CHECK-NEXT: to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]
124 // CHECK: [[EHCLEANUP_BB]]:
125 // CHECK-NEXT: %[[CLEANUPPAD:.*]] = cleanuppad within none []
126 // CHECK-NEXT: call noundef ptr @_ZN7CleanupD1Ev(ptr {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
127 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD]] unwind to caller
129 // Possibly throwing function call within a catch
138 // CHECK-LABEL: @_Z5test4v()
140 // CHECK: %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller
142 // CHECK: [[CATCHSTART_BB]]:
143 // CHECK: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi]
145 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
146 // CHECK-NEXT: to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]
148 // CHECK: [[INVOKE_CONT_BB]]:
149 // CHECK-NEXT: call void @__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
150 // CHECK-NEXT: catchret from %[[CATCHPAD]] to label
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
157 // Possibly throwing function call within a catch-all
166 // CHECK-LABEL: @_Z5test5v()
168 // CHECK: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller
170 // CHECK: [[CATCHSTART_BB]]:
171 // CHECK: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr null]
173 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
174 // CHECK-NEXT: to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]
176 // CHECK: [[INVOKE_CONT_BB0]]:
177 // CHECK-NEXT: call void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]
178 // CHECK-NEXT: catchret from %[[CATCHPAD]] to label
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:.*]]
185 // CHECK: [[INVOKE_CONT_BB1]]:
186 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD0]] unwind to caller
188 // CHECK: [[TERMINATE_BB]]:
189 // CHECK-NEXT: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []
190 // CHECK-NEXT: call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
191 // CHECK-NEXT: unreachable
193 // Try-catch with cleanups
205 // CHECK-LABEL: @_Z5test6v()
206 // CHECK: invoke void @_Z9may_throwv()
207 // CHECK-NEXT: to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]
209 // CHECK: [[EHCLEANUP_BB0]]:
210 // CHECK-NEXT: %[[CLEANUPPAD0:.*]] = cleanuppad within none []
211 // CHECK-NEXT: call noundef ptr @_ZN7CleanupD1Ev(ptr {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
212 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]
214 // CHECK: [[CATCH_DISPATCH_BB]]:
215 // CHECK-NEXT: %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]
217 // CHECK: [[CATCHSTART_BB]]:
218 // CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [ptr @_ZTIi]
219 // CHECK: br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]
221 // CHECK: [[CATCH_INT_BB]]:
222 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
223 // CHECK-NEXT: to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]
225 // CHECK: [[INVOKE_CONT_BB]]:
226 // CHECK: catchret from %[[CATCHPAD]] to label %{{.*}}
228 // CHECK: [[RETHROW_BB]]:
229 // CHECK-NEXT: invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
230 // CHECK-NEXT: to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]
232 // CHECK: [[EHCLEANUP_BB2]]:
233 // CHECK-NEXT: %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
234 // CHECK-NEXT: call noundef ptr @_ZN7CleanupD1Ev(ptr {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
235 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]
237 // CHECK: [[EHCLEANUP_BB3]]:
238 // CHECK-NEXT: %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
239 // CHECK: cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]
241 // CHECK: [[EHCLEANUP_BB1]]:
242 // CHECK-NEXT: %[[CLEANUPPAD1:.*]] = cleanuppad within none []
243 // CHECK-NEXT: call noundef ptr @_ZN7CleanupD1Ev(ptr {{[^,]*}} %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
244 // CHECK-NEXT: cleanupret from %[[CLEANUPPAD1]] unwind to caller
246 // CHECK: [[UNREACHABLE_BB]]:
247 // CHECK-NEXT: unreachable
249 // Nested try-catches within a try with cleanups
271 // CHECK-LABEL: @_Z5test7v()
272 // CHECK: invoke void @_Z9may_throwv()
274 // CHECK: invoke void @_Z9may_throwv()
276 // CHECK: invoke void @_Z9may_throwv()
278 // CHECK: %[[CLEANUPPAD0:.*]] = cleanuppad within none []
279 // CHECK: cleanupret from %[[CLEANUPPAD0]] unwind label
281 // CHECK: %[[CATCHSWITCH0:.*]] = catchswitch within none
283 // CHECK: %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [ptr @_ZTIi, ptr @_ZTId]
285 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
287 // CHECK: catchret from %[[CATCHPAD0]] to label
289 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
291 // CHECK: catchret from %[[CATCHPAD0]] to label
293 // CHECK: invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
295 // CHECK: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
296 // CHECK: cleanupret from %[[CLEANUPPAD1]] unwind label
298 // CHECK: %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
299 // CHECK: cleanupret from %[[CLEANUPPAD2]] unwind label
301 // CHECK: %[[CLEANUPPAD3:.*]] = cleanuppad within none []
302 // CHECK: cleanupret from %[[CLEANUPPAD3]] unwind label
304 // CHECK: %[[CATCHSWITCH1:.*]] = catchswitch within none
306 // CHECK: %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [ptr @_ZTIi, ptr null]
308 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
310 // CHECK: catchret from %[[CATCHPAD1]] to label
312 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
314 // CHECK: invoke void @__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]
316 // CHECK: catchret from %[[CATCHPAD1]] to label
318 // CHECK: %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
319 // CHECK: invoke void @__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]
321 // CHECK: cleanupret from %[[CLEANUPPAD4]] unwind label
323 // CHECK: %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
324 // CHECK: cleanupret from %[[CLEANUPPAD5]] unwind label
326 // CHECK: %[[CLEANUPPAD6:.*]] = cleanuppad within none []
327 // CHECK: cleanupret from %[[CLEANUPPAD6]] unwind to caller
329 // CHECK: unreachable
331 // CHECK: %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
332 // CHECK: call void @_ZSt9terminatev() {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
333 // CHECK: unreachable
335 // Nested try-catches within a catch
348 // CHECK-LABEL: @_Z5test8v()
349 // CHECK: invoke void @_Z9may_throwv()
351 // CHECK: %[[CATCHSWITCH0:.*]] = catchswitch within none
353 // CHECK: %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [ptr @_ZTIi]
355 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]
357 // CHECK: %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]
359 // CHECK: %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [ptr @_ZTIi]
361 // CHECK: invoke void @_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]
363 // CHECK: catchret from %[[CATCHPAD1]] to label
365 // CHECK: invoke void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]
367 // CHECK: catchret from %[[CATCHPAD0]] to label
369 // CHECK: call void @llvm.wasm.rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
370 // CHECK: unreachable
372 // CHECK: %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
373 // CHECK: cleanupret from %[[CLEANUPPAD0]] unwind label
375 // CHECK: %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
376 // CHECK: cleanupret from %[[CLEANUPPAD1]] unwind to caller
378 // CHECK: unreachable
380 // RUN: %clang_cc1 %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
381 // RUN: %clang_cc1 %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
382 // RUN: %clang_cc1 %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
383 // RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fexceptions -fcxx-exceptions -emit-llvm -o - -std=c++11 2>&1 | FileCheck %s --check-prefix=EM-EH-WARNING
385 // Wasm EH ignores dynamic exception specifications with types at the moment.
386 // This is controlled by -Wwasm-exception-spec, which is on by default. This
387 // warning can be suppressed with -Wno-wasm-exception-spec. Checks if a warning
388 // message is correctly printed or not printed depending on the options.
389 void test9() throw(int) {
391 // WARNING-DEFAULT: warning: dynamic exception specifications with types are currently ignored in wasm
392 // WARNING-ON: warning: dynamic exception specifications with types are currently ignored in wasm
393 // WARNING-OFF-NOT: warning: dynamic exception specifications with types are currently ignored in wasm
394 // EM-EH-WARNING: warning: dynamic exception specifications with types are currently ignored in wasm
396 // Wasm curremtly treats 'throw()' in the same way as 'noexept'. Check if the
397 // same warning message is printed as if when a 'noexcept' function throws.
398 void test10() throw() {
401 // WARNING-DEFAULT: warning: 'test10' has a non-throwing exception specification but can still throw
402 // WARNING-DEFAULT: function declared non-throwing here
404 // Here we only check if the command enables wasm exception handling in the
405 // backend so that exception handling instructions can be generated in .s file.
407 // RUN: %clang_cc1 %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