460 lines · cpp
1// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.13.99 -std=c++11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,UNALIGNED,THROWEND %s2// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.14 -std=c++11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ALIGNED,THROWEND %s3// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.14 -std=c++11 -emit-llvm -o - %s -fassume-nothrow-exception-dtor -DNOTHROWEND | FileCheck --check-prefixes=CHECK,ALIGNED,NOTHROWEND %s4 5struct test1_D {6 double d;7} d1;8 9void test1() {10 throw d1;11}12 13// CHECK-LABEL: define{{.*}} void @_Z5test1v()14// CHECK: [[EXNOBJ:%.*]] = call ptr @__cxa_allocate_exception(i64 8)15// UNALIGNED-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[EXNOBJ]], ptr align 8 @d1, i64 8, i1 false)16// ALIGNED-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[EXNOBJ]], ptr align 8 @d1, i64 8, i1 false)17// CHECK-NEXT: call void @__cxa_throw(ptr [[EXNOBJ]], ptr @_ZTI7test1_D, ptr null) [[NR:#[0-9]+]]18// CHECK-NEXT: unreachable19 20 21struct test2_D {22 test2_D(const test2_D&o);23 test2_D();24 virtual void bar() { }25 int i; int j;26} d2;27 28void test2() {29 throw d2;30}31 32// CHECK-LABEL: define{{.*}} void @_Z5test2v()33// CHECK: [[EXNVAR:%.*]] = alloca ptr34// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i3235// CHECK-NEXT: [[EXNOBJ:%.*]] = call ptr @__cxa_allocate_exception(i64 16)36// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_(ptr {{[^,]*}} [[EXNOBJ]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @d2)37// CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}}38// : [[CONT]]: (can't check this in Release-Asserts builds)39// CHECK: call void @__cxa_throw(ptr [[EXNOBJ]], ptr @_ZTI7test2_D, ptr null) [[NR]]40// CHECK-NEXT: unreachable41 42 43struct test3_D {44 test3_D() { }45 test3_D(volatile test3_D&o);46 virtual void bar();47};48 49void test3() {50 throw (volatile test3_D *)0;51}52 53// CHECK-LABEL: define{{.*}} void @_Z5test3v()54// CHECK: [[EXNOBJ:%.*]] = call ptr @__cxa_allocate_exception(i64 8)55// CHECK-NEXT: store ptr null, ptr [[EXNOBJ]]56// CHECK-NEXT: call void @__cxa_throw(ptr [[EXNOBJ]], ptr @_ZTIPV7test3_D, ptr null) [[NR]]57// CHECK-NEXT: unreachable58 59 60void test4() {61 throw;62}63 64// CHECK-LABEL: define{{.*}} void @_Z5test4v()65// CHECK: call void @__cxa_rethrow() [[NR]]66// CHECK-NEXT: unreachable67 68namespace test5 {69 struct A {70 A();71 A(const A&);72 ~A();73 };74 75 void test() {76 try { throw A(); } catch (A &x) {}77 }78// CHECK-LABEL: define{{.*}} void @_ZN5test54testEv()79// CHECK: [[EXNOBJ:%.*]] = call ptr @__cxa_allocate_exception(i64 1)80// CHECK: invoke void @_ZN5test51AC1Ev(ptr {{[^,]*}} [[EXNOBJ]])81// CHECK: invoke void @__cxa_throw(ptr [[EXNOBJ]], ptr @_ZTIN5test51AE, ptr @_ZN5test51AD1Ev) [[NR]]82// CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]]83// : [[HANDLER]]: (can't check this in Release-Asserts builds)84// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIN5test51AE)85}86 87namespace test6 {88 template <class T> struct allocator {89 ~allocator() throw() { }90 };91 92 void foo() {93 allocator<int> a;94 }95}96 97// PR712798namespace test7 {99// CHECK-LABEL: define{{.*}} i32 @_ZN5test73fooEv()100// CHECK-SAME: personality ptr @__gxx_personality_v0101 int foo() {102// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca ptr103// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32104// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32105 try {106 try {107// CHECK-NEXT: [[EXNALLOC:%.*]] = call ptr @__cxa_allocate_exception108// CHECK-NEXT: store i32 1, ptr109// CHECK-NEXT: invoke void @__cxa_throw(ptr [[EXNALLOC]], ptr @_ZTIi, ptr null110 throw 1;111 }112 113// CHECK: [[CAUGHTVAL:%.*]] = landingpad { ptr, i32 }114// CHECK-NEXT: catch ptr @_ZTIi115// CHECK-NEXT: catch ptr null116// CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { ptr, i32 } [[CAUGHTVAL]], 0117// CHECK-NEXT: store ptr [[CAUGHTEXN]], ptr [[CAUGHTEXNVAR]]118// CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { ptr, i32 } [[CAUGHTVAL]], 1119// CHECK-NEXT: store i32 [[SELECTOR]], ptr [[SELECTORVAR]]120// CHECK-NEXT: br label121// CHECK: [[SELECTOR:%.*]] = load i32, ptr [[SELECTORVAR]]122// CHECK-NEXT: [[T0:%.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)123// CHECK-NEXT: icmp eq i32 [[SELECTOR]], [[T0]]124// CHECK-NEXT: br i1125// CHECK: [[T0:%.*]] = load ptr, ptr [[CAUGHTEXNVAR]]126// CHECK-NEXT: [[T1:%.*]] = call ptr @__cxa_begin_catch(ptr [[T0]])127// CHECK-NEXT: [[T3:%.*]] = load i32, ptr [[T1]]128// CHECK-NEXT: store i32 [[T3]], ptr {{%.*}}, align 4129// CHECK-NEXT: invoke void @__cxa_rethrow130 catch (int) {131 throw;132 }133 }134// CHECK: [[CAUGHTVAL:%.*]] = landingpad { ptr, i32 }135// CHECK-NEXT: catch ptr null136// CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { ptr, i32 } [[CAUGHTVAL]], 0137// CHECK-NEXT: store ptr [[CAUGHTEXN]], ptr [[CAUGHTEXNVAR]]138// CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { ptr, i32 } [[CAUGHTVAL]], 1139// CHECK-NEXT: store i32 [[SELECTOR]], ptr [[SELECTORVAR]]140// CHECK-NEXT: call void @__cxa_end_catch()141// CHECK-NEXT: br label142// CHECK: load ptr, ptr [[CAUGHTEXNVAR]]143// CHECK-NEXT: call ptr @__cxa_begin_catch144// CHECK-NEXT: call void @__cxa_end_catch145 catch (...) {146 }147// CHECK: ret i32 0148 return 0;149 }150}151 152// Ordering of destructors in a catch handler.153namespace test8 {154 struct A { A(const A&); ~A(); };155 void bar();156 157 // CHECK-LABEL: define{{.*}} void @_ZN5test83fooEv()158 void foo() {159 try {160 // CHECK: invoke void @_ZN5test83barEv()161 bar();162 } catch (A a) {163 // CHECK: call ptr @__cxa_get_exception_ptr164 // CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(165 // CHECK: call ptr @__cxa_begin_catch166 // CHECK-NEXT: call void @_ZN5test81AD1Ev(167 // CHECK: call void @__cxa_end_catch()168 // CHECK: ret void169 }170 }171}172 173// Constructor function-try-block must rethrow on fallthrough.174namespace test9 {175 void opaque();176 177 struct A { A(); };178 179 180 // CHECK-LABEL: define{{.*}} void @_ZN5test91AC2Ev(ptr {{[^,]*}} %this) unnamed_addr181 // CHECK-SAME: personality ptr @__gxx_personality_v0182 A::A() try {183 // CHECK: invoke void @_ZN5test96opaqueEv()184 opaque();185 } catch (int x) {186 // CHECK: landingpad { ptr, i32 }187 // CHECK-NEXT: catch ptr @_ZTIi188 189 // CHECK: call ptr @__cxa_begin_catch190 // CHECK: invoke void @_ZN5test96opaqueEv()191 // CHECK: invoke void @__cxa_rethrow()192 193 // CHECK-LABEL: define{{.*}} void @_ZN5test91AC1Ev(ptr {{[^,]*}} %this) unnamed_addr194 // CHECK: call void @_ZN5test91AC2Ev195 // CHECK-NEXT: ret void196 opaque();197 }198}199 200// __cxa_end_catch can throw for some kinds of caught exceptions.201namespace test10 {202 void opaque();203 204 struct A { ~A(); };205 struct B { int x; };206 207 // CHECK-LABEL: define{{.*}} void @_ZN6test103fooEv()208 void foo() {209 A a; // force a cleanup context210 211 try {212 // CHECK: invoke void @_ZN6test106opaqueEv()213 opaque();214 } catch (int i) {215 // CHECK: call ptr @__cxa_begin_catch216 // CHECK-NEXT: load i32, ptr217 // CHECK-NEXT: store i32218 // CHECK-NEXT: call void @__cxa_end_catch() [[NUW:#[0-9]+]]219 } catch (B a) {220 // CHECK: call ptr @__cxa_begin_catch221 // CHECK-NEXT: call void @llvm.memcpy222 // THROWEND-NEXT: invoke void @__cxa_end_catch()223 // NOTHROWEND-NEXT: call void @__cxa_end_catch() [[NUW]]224 } catch (...) {225 // CHECK: call ptr @__cxa_begin_catch226 // THROWEND-NEXT: invoke void @__cxa_end_catch()227 // NOTHROWEND-NEXT: call void @__cxa_end_catch() [[NUW]]228 }229 230 // THROWEND: call void @_ZN6test101AD1Ev(231 // NOTHROWEND-NOT: call void @_ZN6test101AD1Ev(232 }233}234 235// __cxa_begin_catch returns pointers by value, even when catching by reference236namespace test11 {237 void opaque();238 239 // CHECK-LABEL: define{{.*}} void @_ZN6test113fooEv()240 void foo() {241 try {242 // CHECK: invoke void @_ZN6test116opaqueEv()243 opaque();244 } catch (int**&p) {245 // CHECK: [[EXN:%.*]] = load ptr, ptr246 // CHECK-NEXT: call ptr @__cxa_begin_catch(ptr [[EXN]]) [[NUW]]247 // CHECK-NEXT: [[ADJ1:%.*]] = getelementptr i8, ptr [[EXN]], i32 32248 // CHECK-NEXT: store ptr [[ADJ1]], ptr [[P:%.*]]249 // CHECK-NEXT: call void @__cxa_end_catch() [[NUW]]250 }251 }252 253 struct A {};254 255 // CHECK-LABEL: define{{.*}} void @_ZN6test113barEv()256 void bar() {257 try {258 // CHECK: [[EXNSLOT:%.*]] = alloca ptr259 // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32260 // CHECK-NEXT: [[P:%.*]] = alloca ptr,261 // CHECK-NEXT: [[TMP:%.*]] = alloca ptr262 // CHECK-NEXT: invoke void @_ZN6test116opaqueEv()263 opaque();264 } catch (A*&p) {265 // CHECK: [[EXN:%.*]] = load ptr, ptr [[EXNSLOT]]266 // CHECK-NEXT: [[ADJ1:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) [[NUW]]267 // CHECK-NEXT: store ptr [[ADJ1]], ptr [[TMP]]268 // CHECK-NEXT: store ptr [[TMP]], ptr [[P]]269 // CHECK-NEXT: call void @__cxa_end_catch() [[NUW]]270 }271 }272}273 274// PR7686275namespace test12 {276 struct A { ~A() noexcept(false); };277 bool opaque(const A&);278 279 // CHECK-LABEL: define{{.*}} void @_ZN6test124testEv()280 void test() {281 // CHECK: [[X:%.*]] = alloca [[A:%.*]],282 // CHECK: [[EHCLEANUPDEST:%.*]] = alloca i32283 // CHECK: [[Y:%.*]] = alloca [[A:%.*]]284 // CHECK: [[Z:%.*]] = alloca [[A]]285 // CHECK: [[CLEANUPDEST:%.*]] = alloca i32286 287 A x;288 // CHECK: invoke noundef zeroext i1 @_ZN6test126opaqueERKNS_1AE(289 if (opaque(x)) {290 A y;291 A z;292 293 // CHECK: invoke void @_ZN6test121AD1Ev(ptr {{[^,]*}} [[Z]])294 // CHECK: invoke void @_ZN6test121AD1Ev(ptr {{[^,]*}} [[Y]])295 // CHECK-NOT: switch296 goto success;297 }298 299 success:300 bool _ = true;301 302 // CHECK: call void @_ZN6test121AD1Ev(ptr {{[^,]*}} [[X]])303 // CHECK-NEXT: ret void304 }305}306 307// Reduced from some TableGen code that was causing a self-host crash.308namespace test13 {309 struct A { ~A(); };310 311 void test0(int x) {312 try {313 switch (x) {314 case 0:315 break;316 case 1:{317 A a;318 break;319 }320 default:321 return;322 }323 return;324 } catch (int x) {325 }326 return;327 }328 329 void test1(int x) {330 A y;331 try {332 switch (x) {333 default: break;334 }335 } catch (int x) {}336 }337}338 339namespace test14 {340 struct A { ~A(); };341 struct B { ~B(); };342 343 B b();344 void opaque();345 346 void foo() {347 A a;348 try {349 B str = b();350 opaque();351 } catch (int x) {352 }353 }354}355 356// JumpDests shouldn't get confused by scopes that aren't normal cleanups.357namespace test15 {358 struct A { ~A(); };359 360 bool opaque(int);361 362 // CHECK-LABEL: define{{.*}} void @_ZN6test153fooEv()363 void foo() {364 A a;365 366 try {367 // CHECK: [[X:%.*]] = alloca i32368 // CHECK: store i32 10, ptr [[X]]369 // CHECK-NEXT: br label370 // -> while.cond371 int x = 10;372 373 while (true) {374 // CHECK: load i32, ptr [[X]]375 // CHECK-NEXT: [[COND:%.*]] = invoke noundef zeroext i1 @_ZN6test156opaqueEi376 // CHECK: br i1 [[COND]]377 if (opaque(x))378 // CHECK: br label379 break;380 381 // CHECK: br label382 }383 // CHECK: br label384 } catch (int x) { }385 386 // CHECK: call void @_ZN6test151AD1Ev387 }388}389 390namespace test16 {391 struct A { A(); ~A() noexcept(false); };392 struct B { int x; B(const A &); ~B() noexcept(false); };393 void foo();394 bool cond();395 396 // CHECK-LABEL: define{{.*}} void @_ZN6test163barEv()397 void bar() {398 // THROWEND: [[EXN_SAVE:%.*]] = alloca ptr399 // THROWEND-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1400 // THROWEND-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]],401 // THROWEND-NEXT: [[EXNSLOT:%.*]] = alloca ptr402 // THROWEND-NEXT: [[SELECTORSLOT:%.*]] = alloca i32403 // THROWEND-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1404 405#ifndef NOTHROWEND406 cond() ? throw B(A()) : foo();407#endif408 409 // THROWEND-NEXT: [[COND:%.*]] = call noundef zeroext i1 @_ZN6test164condEv()410 // THROWEND-NEXT: store i1 false, ptr [[EXN_ACTIVE]]411 // THROWEND-NEXT: store i1 false, ptr [[TEMP_ACTIVE]]412 // THROWEND-NEXT: br i1 [[COND]],413 414 // THROWEND: [[EXN:%.*]] = call ptr @__cxa_allocate_exception(i64 4)415 // THROWEND-NEXT: store ptr [[EXN]], ptr [[EXN_SAVE]]416 // THROWEND-NEXT: store i1 true, ptr [[EXN_ACTIVE]]417 // THROWEND-NEXT: invoke void @_ZN6test161AC1Ev(ptr {{[^,]*}} [[TEMP]])418 // THROWEND: store i1 true, ptr [[TEMP_ACTIVE]]419 // THROWEND-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE(ptr {{[^,]*}} [[EXN]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[TEMP]])420 // THROWEND: store i1 false, ptr [[EXN_ACTIVE]]421 // THROWEND-NEXT: invoke void @__cxa_throw(ptr [[EXN]],422 423 // THROWEND: invoke void @_ZN6test163fooEv()424 // THROWEND: br label425 426 // THROWEND: invoke void @_ZN6test161AD1Ev(ptr {{[^,]*}} [[TEMP]])427 // THROWEND: ret void428 429 // THROWEND: [[T0:%.*]] = load i1, ptr [[EXN_ACTIVE]]430 // THROWEND-NEXT: br i1 [[T0]]431 // THROWEND: [[T1:%.*]] = load ptr, ptr [[EXN_SAVE]]432 // THROWEND-NEXT: call void @__cxa_free_exception(ptr [[T1]])433 // THROWEND-NEXT: br label434 }435}436 437namespace test17 {438class BaseException {439private:440 int a[4];441public:442 BaseException() {};443};444 445class DerivedException: public BaseException {446};447 448int foo() {449 throw DerivedException();450 // The alignment passed to memset is 16 on Darwin.451 452 // CHECK: [[T0:%.*]] = call ptr @__cxa_allocate_exception(i64 16)453 // UNALIGNED-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[T0]], i8 0, i64 16, i1 false)454 // ALIGNED-NEXT: call void @llvm.memset.p0.i64(ptr align 16 [[T0]], i8 0, i64 16, i1 false)455}456}457 458// CHECK: attributes [[NUW]] = { nounwind }459// CHECK: attributes [[NR]] = { noreturn }460