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