675 lines · plain
1; RUN: llc < %s -asm-verbose=false -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s2; RUN: llc < %s -asm-verbose=false -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs -O03; RUN: llc < %s -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling4; RUN: llc < %s -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -filetype=obj5; RUN: llc < %s -mtriple=wasm64-unknown-unknown -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s --check-prefix=WASM646 7target triple = "wasm32-unknown-unknown"8 9%struct.Temp = type { i8 }10 11@_ZTIi = external dso_local constant ptr12 13; CHECK: .tagtype __cpp_exception i3214 15; CHECK-LABEL: throw:16; CHECK: throw __cpp_exception17; CHECK-NOT: unreachable18define void @throw(ptr %p) {19 call void @llvm.wasm.throw(i32 0, ptr %p)20 ret void21}22 23; Simple test with a try-catch24;25; void foo();26; void catch() {27; try {28; foo();29; } catch (int) {30; }31; }32 33; CHECK-LABEL: catch:34; WASM64-LABEL: catch:35; CHECK: global.get __stack_pointer36; CHECK: local.set 037; CHECK: block38; CHECK: block () -> (i32, exnref)39; CHECK: try_table (catch_ref __cpp_exception 0)40; WASM64: block () -> (i64, exnref)41; CHECK: call foo42; CHECK: br 243; CHECK: end_try_table44; CHECK: unreachable45; CHECK: end_block46; CHECK: local.set 247; CHECK: local.get 048; CHECK: global.set __stack_pointer49; CHECK: i32.store __wasm_lpad_context50; CHECK: call _Unwind_CallPersonality51; CHECK: block52; CHECK: br_if 053; CHECK: call __cxa_begin_catch54; CHECK: call __cxa_end_catch55; CHECK: br 156; CHECK: end_block57; CHECK: local.get 258; CHECK: throw_ref59; CHECK: end_block60define void @catch() personality ptr @__gxx_wasm_personality_v0 {61entry:62 invoke void @foo()63 to label %try.cont unwind label %catch.dispatch64 65catch.dispatch: ; preds = %entry66 %0 = catchswitch within none [label %catch.start] unwind to caller67 68catch.start: ; preds = %catch.dispatch69 %1 = catchpad within %0 [ptr @_ZTIi]70 %2 = call ptr @llvm.wasm.get.exception(token %1)71 %3 = call i32 @llvm.wasm.get.ehselector(token %1)72 %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)73 %matches = icmp eq i32 %3, %474 br i1 %matches, label %catch, label %rethrow75 76catch: ; preds = %catch.start77 %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]78 call void @__cxa_end_catch() [ "funclet"(token %1) ]79 catchret from %1 to label %try.cont80 81rethrow: ; preds = %catch.start82 call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]83 unreachable84 85try.cont: ; preds = %catch, %entry86 ret void87}88 89; Destructor (cleanup) test90;91; void foo();92; struct Temp {93; ~Temp() {}94; };95; void cleanup() {96; Temp t;97; foo();98; }99 100; CHECK-LABEL: cleanup:101; CHECK: block102; CHECK: block exnref103; CHECK: try_table (catch_all_ref 0)104; CHECK: call foo105; CHECK: br 2106; CHECK: end_try_table107; CHECK: end_block108; CHECK: local.set 1109; CHECK: global.set __stack_pointer110; CHECK: call _ZN4TempD2Ev111; CHECK: local.get 1112; CHECK: throw_ref113; CHECK: end_block114; CHECK: call _ZN4TempD2Ev115define void @cleanup() personality ptr @__gxx_wasm_personality_v0 {116entry:117 %t = alloca %struct.Temp, align 1118 invoke void @foo()119 to label %invoke.cont unwind label %ehcleanup120 121invoke.cont: ; preds = %entry122 %call = call ptr @_ZN4TempD2Ev(ptr %t)123 ret void124 125ehcleanup: ; preds = %entry126 %0 = cleanuppad within none []127 %call1 = call ptr @_ZN4TempD2Ev(ptr %t) [ "funclet"(token %0) ]128 cleanupret from %0 unwind to caller129}130 131; Calling a function that may throw within a 'catch (...)' generates a132; terminatepad, because __cxa_end_catch() also can throw within 'catch (...)'.133;134; void foo();135; void terminatepad() {136; try {137; foo();138; } catch (...) {139; foo();140; }141; }142 143; CHECK-LABEL: terminatepad144; WASM64-LABEL: terminatepad145; CHECK: block146; CHECK: block i32147; WASM64: block i64148; CHECK: try_table (catch __cpp_exception 0)149; CHECK: call foo150; CHECK: br 2151; CHECK: end_try_table152; CHECK: end_block153; CHECK: call __cxa_begin_catch154; CHECK: block155; CHECK: block exnref156; CHECK: try_table (catch_all_ref 0)157; CHECK: call foo158; CHECK: br 2159; CHECK: end_try_table160; CHECK: end_block161; CHECK: local.set 2162; CHECK: block163; CHECK: block164; CHECK: try_table (catch_all 0)165; CHECK: call __cxa_end_catch166; CHECK: br 2167; CHECK: end_try_table168; CHECK: end_block169; CHECK: call _ZSt9terminatev170; CHECK: unreachable171; CHECK: end_block172; CHECK: local.get 2173; CHECK: throw_ref174; CHECK: end_block175; CHECK: call __cxa_end_catch176; CHECK: end_block177define void @terminatepad() personality ptr @__gxx_wasm_personality_v0 {178entry:179 invoke void @foo()180 to label %try.cont unwind label %catch.dispatch181 182catch.dispatch: ; preds = %entry183 %0 = catchswitch within none [label %catch.start] unwind to caller184 185catch.start: ; preds = %catch.dispatch186 %1 = catchpad within %0 [ptr null]187 %2 = call ptr @llvm.wasm.get.exception(token %1)188 %3 = call i32 @llvm.wasm.get.ehselector(token %1)189 %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]190 invoke void @foo() [ "funclet"(token %1) ]191 to label %invoke.cont1 unwind label %ehcleanup192 193invoke.cont1: ; preds = %catch.start194 call void @__cxa_end_catch() [ "funclet"(token %1) ]195 catchret from %1 to label %try.cont196 197try.cont: ; preds = %invoke.cont1, %entry198 ret void199 200ehcleanup: ; preds = %catch.start201 %5 = cleanuppad within %1 []202 invoke void @__cxa_end_catch() [ "funclet"(token %5) ]203 to label %invoke.cont2 unwind label %terminate204 205invoke.cont2: ; preds = %ehcleanup206 cleanupret from %5 unwind to caller207 208terminate: ; preds = %ehcleanup209 %6 = cleanuppad within %5 []210 call void @_ZSt9terminatev() #2 [ "funclet"(token %6) ]211 unreachable212}213 214; Tests prologues and epilogues are not generated within EH scopes.215; They should not be treated as funclets; BBs starting with a catch instruction216; should not have a prologue, and BBs ending with a catchret/cleanupret should217; not have an epilogue. This is separate from __stack_pointer restoring218; instructions after a catch instruction.219;220; void bar(int) noexcept;221; void no_prolog_epilog_in_ehpad() {222; int stack_var = 0;223; bar(stack_var);224; try {225; foo();226; } catch (int) {227; foo();228; }229; }230 231; CHECK-LABEL: no_prolog_epilog_in_ehpad232; CHECK: call bar233; CHECK: block234; CHECK: block () -> (i32, exnref)235; CHECK: try_table (catch_ref __cpp_exception 0)236; CHECK: call foo237; CHECK: br 2238; CHECK: end_try_table239; CHECK: end_block240; CHECK: local.set 2241; CHECK-NOT: global.get __stack_pointer242; CHECK: global.set __stack_pointer243; CHECK: block244; CHECK: block245; CHECK: br_if 0246; CHECK: call __cxa_begin_catch247; CHECK: block exnref248; CHECK: try_table (catch_all_ref 0)249; CHECK: call foo250; CHECK: br 3251; CHECK: end_try_table252; CHECK: end_block253; CHECK: local.set 2254; CHECK-NOT: global.get __stack_pointer255; CHECK: global.set __stack_pointer256; CHECK: call __cxa_end_catch257; CHECK: local.get 2258; CHECK: throw_ref259; CHECK-NOT: global.set __stack_pointer260; CHECK: end_block261; CHECK: local.get 2262; CHECK: throw_ref263; CHECK: end_block264; CHECK-NOT: global.set __stack_pointer265; CHECK: call __cxa_end_catch266; CHECK: end_block267define void @no_prolog_epilog_in_ehpad() personality ptr @__gxx_wasm_personality_v0 {268entry:269 %stack_var = alloca i32, align 4270 call void @bar(ptr %stack_var)271 invoke void @foo()272 to label %try.cont unwind label %catch.dispatch273 274catch.dispatch: ; preds = %entry275 %0 = catchswitch within none [label %catch.start] unwind to caller276 277catch.start: ; preds = %catch.dispatch278 %1 = catchpad within %0 [ptr @_ZTIi]279 %2 = call ptr @llvm.wasm.get.exception(token %1)280 %3 = call i32 @llvm.wasm.get.ehselector(token %1)281 %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)282 %matches = icmp eq i32 %3, %4283 br i1 %matches, label %catch, label %rethrow284 285catch: ; preds = %catch.start286 %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]287 %6 = load float, ptr %5, align 4288 invoke void @foo() [ "funclet"(token %1) ]289 to label %invoke.cont1 unwind label %ehcleanup290 291invoke.cont1: ; preds = %catch292 call void @__cxa_end_catch() [ "funclet"(token %1) ]293 catchret from %1 to label %try.cont294 295rethrow: ; preds = %catch.start296 call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]297 unreachable298 299try.cont: ; preds = %invoke.cont1, %entry300 ret void301 302ehcleanup: ; preds = %catch303 %7 = cleanuppad within %1 []304 call void @__cxa_end_catch() [ "funclet"(token %7) ]305 cleanupret from %7 unwind to caller306}307 308; When a function does not have stack-allocated objects, it does not need to309; store SP back to __stack_pointer global at the epilog.310;311; void foo();312; void no_sp_writeback() {313; try {314; foo();315; } catch (...) {316; }317; }318 319; CHECK-LABEL: no_sp_writeback320; CHECK: block321; CHECK: block i32322; CHECK: try_table (catch __cpp_exception 0)323; CHECK: call foo324; CHECK: br 2325; CHECK: end_try_table326; CHECK: end_block327; CHECK: call __cxa_begin_catch328; CHECK: call __cxa_end_catch329; CHECK: end_block330; CHECK-NOT: global.set __stack_pointer331; CHECK: end_function332define void @no_sp_writeback() personality ptr @__gxx_wasm_personality_v0 {333entry:334 invoke void @foo()335 to label %try.cont unwind label %catch.dispatch336 337catch.dispatch: ; preds = %entry338 %0 = catchswitch within none [label %catch.start] unwind to caller339 340catch.start: ; preds = %catch.dispatch341 %1 = catchpad within %0 [ptr null]342 %2 = call ptr @llvm.wasm.get.exception(token %1)343 %3 = call i32 @llvm.wasm.get.ehselector(token %1)344 %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]345 call void @__cxa_end_catch() [ "funclet"(token %1) ]346 catchret from %1 to label %try.cont347 348try.cont: ; preds = %catch.start, %entry349 ret void350}351 352; When the result of @llvm.wasm.get.exception is not used. This is created to353; fix a bug in LateEHPrepare and this should not crash.354define void @get_exception_wo_use() personality ptr @__gxx_wasm_personality_v0 {355entry:356 invoke void @foo()357 to label %try.cont unwind label %catch.dispatch358 359catch.dispatch: ; preds = %entry360 %0 = catchswitch within none [label %catch.start] unwind to caller361 362catch.start: ; preds = %catch.dispatch363 %1 = catchpad within %0 [ptr null]364 %2 = call ptr @llvm.wasm.get.exception(token %1)365 %3 = call i32 @llvm.wasm.get.ehselector(token %1)366 catchret from %1 to label %try.cont367 368try.cont: ; preds = %catch.start, %entry369 ret void370}371 372; Tests a case when a cleanup region (cleanuppad ~ clanupret) contains another373; catchpad374define void @complex_cleanup_region() personality ptr @__gxx_wasm_personality_v0 {375entry:376 invoke void @foo()377 to label %invoke.cont unwind label %ehcleanup378 379invoke.cont: ; preds = %entry380 ret void381 382ehcleanup: ; preds = %entry383 %0 = cleanuppad within none []384 invoke void @foo() [ "funclet"(token %0) ]385 to label %ehcleanupret unwind label %catch.dispatch386 387catch.dispatch: ; preds = %ehcleanup388 %1 = catchswitch within %0 [label %catch.start] unwind label %ehcleanup.1389 390catch.start: ; preds = %catch.dispatch391 %2 = catchpad within %1 [ptr null]392 %3 = call ptr @llvm.wasm.get.exception(token %2)393 %4 = call i32 @llvm.wasm.get.ehselector(token %2)394 catchret from %2 to label %ehcleanupret395 396ehcleanup.1: ; preds = %catch.dispatch397 %5 = cleanuppad within %0 []398 unreachable399 400ehcleanupret: ; preds = %catch.start, %ehcleanup401 cleanupret from %0 unwind to caller402}403 404; Regression test for the bug that 'rethrow' was not treated correctly as a405; terminator in isel.406define void @rethrow_terminator() personality ptr @__gxx_wasm_personality_v0 {407entry:408 invoke void @foo()409 to label %try.cont unwind label %catch.dispatch410 411catch.dispatch: ; preds = %entry412 %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup413 414catch.start: ; preds = %catch.dispatch415 %1 = catchpad within %0 [ptr @_ZTIi]416 %2 = call ptr @llvm.wasm.get.exception(token %1)417 %3 = call i32 @llvm.wasm.get.ehselector(token %1)418 %4 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)419 %matches = icmp eq i32 %3, %4420 br i1 %matches, label %catch, label %rethrow421 422catch: ; preds = %catch.start423 %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]424 %6 = load i32, ptr %5, align 4425 call void @__cxa_end_catch() [ "funclet"(token %1) ]426 catchret from %1 to label %try.cont427 428rethrow: ; preds = %catch.start429 invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]430 to label %unreachable unwind label %ehcleanup431 432try.cont: ; preds = %entry, %catch433 ret void434 435ehcleanup: ; preds = %rethrow, %catch.dispatch436 ; 'rethrow' BB is this BB's predecessor, and its437 ; 'invoke void @llvm.wasm.rethrow()' is lowered down to a 'RETHROW' in Wasm438 ; MIR. And this 'phi' creates 'CONST_I32' instruction in the predecessor439 ; 'rethrow' BB. If 'RETHROW' is not treated correctly as a terminator, it can440 ; create a BB like441 ; bb.3.rethrow:442 ; RETHROW 0443 ; %0 = CONST_I32 20444 ; BR ...445 %tmp = phi i32 [ 10, %catch.dispatch ], [ 20, %rethrow ]446 %7 = cleanuppad within none []447 call void @take_i32(i32 %tmp) [ "funclet"(token %7) ]448 cleanupret from %7 unwind to caller449 450unreachable: ; preds = %rethrow451 unreachable452}453 454; The bitcode below is generated when the code below is compiled and455; Temp::~Temp() is inlined into inlined_cleanupret():456;457; void inlined_cleanupret() {458; try {459; Temp t;460; throw 2;461; } catch (...)462; }463;464; Temp::~Temp() {465; try {466; throw 1;467; } catch (...) {468; }469; }470;471; ~Temp() generates cleanupret, which is lowered to a 'throw_ref' later. That472; throw_ref's argument should correctly target the top-level cleanuppad473; (catch_all_ref). This is a regression test for the bug where we did not474; compute throw_ref's argument correctly.475 476; CHECK-LABEL: inlined_cleanupret:477; CHECK: block exnref478; CHECK: block479; CHECK: block exnref480; CHECK: try_table (catch_all_ref 0)481; CHECK: call __cxa_throw482; CHECK: end_try_table483; CHECK: end_block484; try_table (catch_all_ref 0)'s caught exception is stored in local 2485; CHECK: local.set 2486; CHECK: block487; CHECK: try_table (catch_all 0)488; CHECK: block489; CHECK: block i32490; CHECK: try_table (catch __cpp_exception 0)491; CHECK: call __cxa_throw492; CHECK: end_try_table493; CHECK: end_block494; CHECK: call __cxa_end_catch495; CHECK: block i32496; CHECK: try_table (catch_all_ref 5)497; CHECK: try_table (catch __cpp_exception 1)498; Note that the throw_ref below targets the top-level catch_all_ref (local 2)499; CHECK: local.get 2500; CHECK: throw_ref501; CHECK: end_try_table502; CHECK: end_try_table503; CHECK: end_block504; CHECK: try_table (catch_all_ref 4)505; CHECK: call __cxa_end_catch506; CHECK: end_try_table507; CHECK: return508; CHECK: end_block509; CHECK: end_try_table510; CHECK: end_block511; CHECK: call _ZSt9terminatev512; CHECK: end_block513; CHECK: end_block514; CHECK: throw_ref515define void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 {516entry:517 %exception = tail call ptr @__cxa_allocate_exception(i32 4)518 store i32 2, ptr %exception, align 16519 invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null)520 to label %unreachable unwind label %ehcleanup521 522ehcleanup: ; preds = %entry523 %0 = cleanuppad within none []524 %exception.i = call ptr @__cxa_allocate_exception(i32 4) [ "funclet"(token %0) ]525 store i32 1, ptr %exception.i, align 16526 invoke void @__cxa_throw(ptr nonnull %exception.i, ptr nonnull @_ZTIi, ptr null) [ "funclet"(token %0) ]527 to label %unreachable unwind label %catch.dispatch.i528 529catch.dispatch.i: ; preds = %ehcleanup530 %1 = catchswitch within %0 [label %catch.start.i] unwind label %terminate.i531 532catch.start.i: ; preds = %catch.dispatch.i533 %2 = catchpad within %1 [ptr null]534 %3 = tail call ptr @llvm.wasm.get.exception(token %2)535 %4 = tail call i32 @llvm.wasm.get.ehselector(token %2)536 %5 = call ptr @__cxa_begin_catch(ptr %3) [ "funclet"(token %2) ]537 invoke void @__cxa_end_catch() [ "funclet"(token %2) ]538 to label %invoke.cont.i unwind label %terminate.i539 540invoke.cont.i: ; preds = %catch.start.i541 catchret from %2 to label %_ZN4TempD2Ev.exit542 543terminate.i: ; preds = %catch.start.i, %catch.dispatch.i544 %6 = cleanuppad within %0 []545 call void @_ZSt9terminatev() #2 [ "funclet"(token %6) ]546 unreachable547 548_ZN4TempD2Ev.exit: ; preds = %invoke.cont.i549 cleanupret from %0 unwind label %catch.dispatch550 551catch.dispatch: ; preds = %_ZN4TempD2Ev.exit552 %7 = catchswitch within none [label %catch.start] unwind to caller553 554catch.start: ; preds = %catch.dispatch555 %8 = catchpad within %7 [ptr null]556 %9 = tail call ptr @llvm.wasm.get.exception(token %8)557 %10 = tail call i32 @llvm.wasm.get.ehselector(token %8)558 %11 = call ptr @__cxa_begin_catch(ptr %9) #8 [ "funclet"(token %8) ]559 call void @__cxa_end_catch() [ "funclet"(token %8) ]560 catchret from %8 to label %try.cont561 562try.cont: ; preds = %catch.start563 ret void564 565unreachable: ; preds = %entry566 unreachable567}568 569; This tests whether llvm.wasm.throw intrinsic can invoked and iseled correctly.570 571; CHECK-LABEL: invoke_throw:572; CHECK: try_table (catch __cpp_exception 0)573; CHECK: local.get 0574; CHECK: throw __cpp_exception575; CHECK: end_try_table576define void @invoke_throw(ptr %p) personality ptr @__gxx_wasm_personality_v0 {577entry:578 invoke void @llvm.wasm.throw(i32 0, ptr %p)579 to label %try.cont unwind label %catch.dispatch580 581catch.dispatch: ; preds = %entry582 %0 = catchswitch within none [label %catch.start] unwind to caller583 584catch.start: ; preds = %catch.dispatch585 %1 = catchpad within %0 [ptr null]586 %2 = call ptr @llvm.wasm.get.exception(token %1)587 %3 = call i32 @llvm.wasm.get.ehselector(token %1)588 %4 = call ptr @__cxa_begin_catch(ptr %2) #4 [ "funclet"(token %1) ]589 call void @__cxa_end_catch() [ "funclet"(token %1) ]590 catchret from %1 to label %try.cont591 592try.cont: ; preds = %catch, %entry593 ret void594}595 596; Regression test for a bug where, when an invoke unwinds to a catchswitch, the597; catchswitch's unwind destination was not included in the invoke's unwind598; destination when there was no direct link from catch.start to there.599 600; CHECK-LABEL: unwind_destinations:601; CHECK: block602; CHECK: block603; CHECK: try_table (catch_all 0)604; CHECK: block i32605; CHECK: try_table (catch __cpp_exception 0)606; CHECK: call foo607; CHECK: end_try_table608; CHECK: unreachable609; CHECK: end_block610; CHECK: call _ZSt9terminatev611; CHECK: unreachable612; CHECK: end_try_table613; CHECK: unreachable614; CHECK: end_block615; Note the below is "terminate" BB and should not be DCE'd616; CHECK: call _ZSt9terminatev617; CHECK: unreachable618; CHECK: end_block619define void @unwind_destinations() personality ptr @__gxx_wasm_personality_v0 {620entry:621 invoke void @foo()622 to label %try.cont unwind label %catch.dispatch623 624catch.dispatch: ; preds = %entry625 %0 = catchswitch within none [label %catch.start] unwind label %terminate626 627catch.start: ; preds = %catch.dispatch628 %1 = catchpad within %0 [ptr null]629 %2 = call ptr @llvm.wasm.get.exception(token %1)630 %3 = call ptr @__cxa_begin_catch(ptr %2) #5 [ "funclet"(token %1) ]631 call void @_ZSt9terminatev() #2 [ "funclet"(token %1) ]632 unreachable633 634; Even if there is no link from catch.start to this terminate BB, when there is635; an exception that catch.start does not catch (e.g. a foreign exception), it636; should end up here, so this BB should NOT be DCE'ed637terminate: ; preds = %catch.dispatch638 %4 = cleanuppad within none []639 call void @_ZSt9terminatev() #2 [ "funclet"(token %4) ]640 unreachable641 642try.cont: ; preds = %entry643 ret void644}645 646declare void @foo()647declare void @bar(ptr)648declare void @take_i32(i32)649declare i32 @__gxx_wasm_personality_v0(...)650; Function Attrs: noreturn651declare void @llvm.wasm.throw(i32, ptr) #1652; Function Attrs: nounwind653declare ptr @llvm.wasm.get.exception(token) #0654; Function Attrs: nounwind655declare i32 @llvm.wasm.get.ehselector(token) #0656; Function Attrs: noreturn657declare void @llvm.wasm.rethrow() #1658; Function Attrs: nounwind659declare i32 @llvm.eh.typeid.for(ptr) #0660; Function Attrs: nounwind661declare ptr @__cxa_allocate_exception(i32) #0662declare ptr @__cxa_begin_catch(ptr)663declare void @__cxa_end_catch()664; Function Attrs: noreturn665declare void @__cxa_throw(ptr, ptr, ptr) #1666declare void @_ZSt9terminatev()667declare ptr @_ZN4TempD2Ev(ptr returned)668 669attributes #0 = { nounwind }670attributes #1 = { noreturn }671attributes #2 = { noreturn nounwind }672 673;; The exception tag should not be defined locally674; CHECK-NOT: __cpp_exception:675