diff options
Diffstat (limited to 'clang/test/CodeGenCXX/exceptions.cpp')
-rw-r--r-- | clang/test/CodeGenCXX/exceptions.cpp | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp new file mode 100644 index 0000000..079c1e5 --- /dev/null +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -0,0 +1,416 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s + +typedef typeof(sizeof(0)) size_t; + +// This just shouldn't crash. +namespace test0 { + struct allocator { + allocator(); + allocator(const allocator&); + ~allocator(); + }; + + void f(); + void g(bool b, bool c) { + if (b) { + if (!c) + throw allocator(); + + return; + } + f(); + } +} + +namespace test1 { + struct A { A(int); A(int, int); ~A(); void *p; }; + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test11aEv() + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(5); + } + + A *b() { + // CHECK: define [[A:%.*]]* @_ZN5test11bEv() + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: [[FOO:%.*]] = invoke i32 @_ZN5test13fooEv() + // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[FOO]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + extern int foo(); + return new A(foo()); + } + + struct B { B(); ~B(); operator int(); int x; }; + B makeB(); + + A *c() { + // CHECK: define [[A:%.*]]* @_ZN5test11cEv() + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]]) + // CHECK: [[T1:%.*]] = getelementptr inbounds [[B]]* [[T0]], i32 0, i32 0 + // CHECK-NEXT: [[T2:%.*]] = load i32* [[T1]], align 4 + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T2]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(B().x); + } + + A *d() { + // CHECK: define [[A:%.*]]* @_ZN5test11dEv() + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]]) + // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) + // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(B()); + } + + A *e() { + // CHECK: define [[A:%.*]]* @_ZN5test11eEv() + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]]) + // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) + // CHECK: invoke void @_ZN5test11BC1Ev([[B]]* [[T2:%.*]]) + // CHECK: [[T3:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T2]]) + // CHECK: invoke void @_ZN5test11AC1Eii([[A]]* [[CAST]], i32 [[T1]], i32 [[T3]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]]) + // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(B(), B()); + } + A *f() { + return new A(makeB().x); + } + A *g() { + return new A(makeB()); + } + A *h() { + return new A(makeB(), makeB()); + } + + A *i() { + // CHECK: define [[A:%.*]]* @_ZN5test11iEv() + // CHECK: [[X:%.*]] = alloca [[A]]*, align 8 + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T0:%.*]]) + // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) + // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: store [[A]]* [[CAST]], [[A]]** [[X]], align 8 + // CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T2:%.*]]) + // CHECK: [[RET:%.*]] = load [[A]]** [[X]], align 8 + // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]]) + // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[RET]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + A *x; + return (x = new A(makeB()), makeB(), x); + } +} + +namespace test2 { + struct A { + A(int); A(int, int); ~A(); + void *p; + void *operator new(size_t); + void operator delete(void*, size_t); + }; + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test21aEv() + // CHECK: [[NEW:%.*]] = call i8* @_ZN5test21AnwEm(i64 8) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test21AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: invoke void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8) + // CHECK: call void @_ZSt9terminatev() + return new A(5); + } +} + +namespace test3 { + struct A { + A(int); A(int, int); A(const A&); ~A(); + void *p; + void *operator new(size_t, void*, double); + void operator delete(void*, void*, double); + }; + + void *foo(); + double bar(); + A makeA(), *makeAPtr(); + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test31aEv() + // CHECK: [[FOO:%.*]] = call i8* @_ZN5test33fooEv() + // CHECK: [[BAR:%.*]] = call double @_ZN5test33barEv() + // CHECK: [[NEW:%.*]] = call i8* @_ZN5test31AnwEmPvd(i64 8, i8* [[FOO]], double [[BAR]]) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test31AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: invoke void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]]) + // CHECK: call void @_ZSt9terminatev() + return new(foo(),bar()) A(5); + } + + // rdar://problem/8439196 + A *b(bool cond) { + + // CHECK: define [[A:%.*]]* @_ZN5test31bEb(i1 zeroext + // CHECK: [[SAVED0:%.*]] = alloca i8* + // CHECK-NEXT: [[SAVED1:%.*]] = alloca i8* + // CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1 + + // CHECK: [[COND:%.*]] = trunc i8 {{.*}} to i1 + // CHECK-NEXT: store i1 false, i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: br i1 [[COND]] + return (cond ? + + // CHECK: [[FOO:%.*]] = call i8* @_ZN5test33fooEv() + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test31AnwEmPvd(i64 8, i8* [[FOO]], double [[CONST:.*]]) + // CHECK-NEXT: store i8* [[NEW]], i8** [[SAVED0]] + // CHECK-NEXT: store i8* [[FOO]], i8** [[SAVED1]] + // CHECK-NEXT: store i1 true, i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret [[CAST]]) + // CHECK: br label + // -> cond.end + new(foo(),10.0) A(makeA()) : + + // CHECK: [[MAKE:%.*]] = call [[A]]* @_ZN5test38makeAPtrEv() + // CHECK: br label + // -> cond.end + makeAPtr()); + + // cond.end: + // CHECK: [[RESULT:%.*]] = phi [[A]]* {{.*}}[[CAST]]{{.*}}[[MAKE]] + // CHECK: ret [[A]]* [[RESULT]] + + // in the EH path: + // CHECK: [[ISACTIVE:%.*]] = load i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: [[V0:%.*]] = load i8** [[SAVED0]] + // CHECK-NEXT: [[V1:%.*]] = load i8** [[SAVED1]] + // CHECK-NEXT: invoke void @_ZN5test31AdlEPvS1_d(i8* [[V0]], i8* [[V1]], double [[CONST]]) + } +} + +namespace test4 { + struct A { + A(int); A(int, int); ~A(); + void *p; + void *operator new(size_t, void*, void*); + void operator delete(void*, size_t, void*, void*); // not a match + }; + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test41aEv() + // CHECK: [[FOO:%.*]] = call i8* @_ZN5test43fooEv() + // CHECK-NEXT: [[BAR:%.*]] = call i8* @_ZN5test43barEv() + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test41AnwEmPvS1_(i64 8, i8* [[FOO]], i8* [[BAR]]) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: call void @_ZN5test41AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK-NEXT: ret [[A]]* [[CAST]] + extern void *foo(), *bar(); + + return new(foo(),bar()) A(5); + } +} + +// PR7908 +namespace test5 { + struct T { T(); ~T(); }; + + struct A { + A(const A &x, const T &t = T()); + ~A(); + }; + + void foo(); + + // CHECK: define void @_ZN5test54testEv() + // CHECK: [[EXNSLOT:%.*]] = alloca i8* + // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 + // CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1 + // CHECK-NEXT: [[T:%.*]] = alloca [[T_T:%.*]], align 1 + // CHECK-NEXT: invoke void @_ZN5test53fooEv() + // CHECK: [[EXN:%.*]] = load i8** [[EXNSLOT]] + // CHECK-NEXT: [[ADJ:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[EXN]]) + // CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[ADJ]] to [[A_T]]* + // CHECK-NEXT: invoke void @_ZN5test51TC1Ev([[T_T]]* [[T]]) + // CHECK: invoke void @_ZN5test51AC1ERKS0_RKNS_1TE([[A_T]]* [[A]], [[A_T]]* [[SRC]], [[T_T]]* [[T]]) + // CHECK: invoke void @_ZN5test51TD1Ev([[T_T]]* [[T]]) + // CHECK: call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind + // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A_T]]* [[A]]) + // CHECK: call void @__cxa_end_catch() + void test() { + try { + foo(); + } catch (A a) { + } + } +} + +// PR9303: invalid assert on this +namespace test6 { + bool cond(); + void test() { + try { + lbl: + if (cond()) goto lbl; + } catch (...) { + } + } +} + +// PR9298 +namespace test7 { + struct A { A(); ~A(); }; + struct B { + // The throw() operator means that a bad allocation is signalled + // with a null return, which means that the initializer is + // evaluated conditionally. + static void *operator new(size_t size) throw(); + B(const A&, B*); + ~B(); + }; + + B *test() { + // CHECK: define [[B:%.*]]* @_ZN5test74testEv() + // CHECK: [[OUTER_NEW:%.*]] = alloca i1 + // CHECK-NEXT: alloca [[A:%.*]], + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: alloca i32 + // CHECK-NEXT: [[OUTER_A:%.*]] = alloca i1 + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: [[INNER_NEW:%.*]] = alloca i1 + // CHECK-NEXT: alloca [[A]] + // CHECK-NEXT: [[INNER_A:%.*]] = alloca i1 + + // Allocate the outer object. + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm( + // CHECK-NEXT: icmp eq i8* [[NEW]], null + + // These stores, emitted before the outermost conditional branch, + // deactivate the temporary cleanups. + // CHECK-NEXT: store i1 false, i1* [[OUTER_NEW]] + // CHECK-NEXT: store i1 false, i1* [[OUTER_A]] + // CHECK-NEXT: store i1 false, i1* [[INNER_NEW]] + // CHECK-NEXT: store i1 false, i1* [[INNER_A]] + // CHECK-NEXT: br i1 + + // We passed the first null check; activate that cleanup and continue. + // CHECK: store i1 true, i1* [[OUTER_NEW]] + // CHECK-NEXT: bitcast + + // Create the first A temporary and activate that cleanup. + // CHECK-NEXT: invoke void @_ZN5test71AC1Ev( + // CHECK: store i1 true, i1* [[OUTER_A]] + + // Allocate the inner object. + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm( + // CHECK-NEXT: icmp eq i8* [[NEW]], null + // CHECK-NEXT: br i1 + + // We passed the second null check; save that pointer, activate + // that cleanup, and continue. + // CHECK: store i8* [[NEW]] + // CHECK-NEXT: store i1 true, i1* [[INNER_NEW]] + // CHECK-NEXT: bitcast + + // Build the second A temporary and activate that cleanup. + // CHECK-NEXT: invoke void @_ZN5test71AC1Ev( + // CHECK: store i1 true, i1* [[INNER_A]] + + // Build the inner B object and deactivate the inner delete cleanup. + // CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_( + // CHECK: store i1 false, i1* [[INNER_NEW]] + // CHECK: phi + + // Build the outer B object and deactivate the outer delete cleanup. + // CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_( + // CHECK: store i1 false, i1* [[OUTER_NEW]] + // CHECK: phi + + // Destroy the inner A object. + // CHECK-NEXT: load i1* [[INNER_A]] + // CHECK-NEXT: br i1 + // CHECK: invoke void @_ZN5test71AD1Ev( + + // Destroy the outer A object. + // CHECK: load i1* [[OUTER_A]] + // CHECK-NEXT: br i1 + // CHECK: invoke void @_ZN5test71AD1Ev( + + return new B(A(), new B(A(), 0)); + } +} + +// Just don't crash. +namespace test8 { + struct A { + // Having both of these is required to trigger the assert we're + // trying to avoid. + A(const A&); + A&operator=(const A&); + + ~A(); + }; + + A makeA(); + void test() { + throw makeA(); + } + // CHECK: define void @_ZN5test84testEv +} + +// Make sure we generate the correct code for the delete[] call which +// happens if A::A() throws. (We were previously calling delete[] on +// a pointer to the first array element, not the pointer returned by new[].) +// PR10870 +namespace test9 { + struct A { + A(); + ~A(); + }; + A* test() { + return new A[10]; + } + // CHECK: define {{%.*}}* @_ZN5test94testEv + // CHECK: [[TEST9_NEW:%.*]] = call noalias i8* @_Znam + // CHECK: call void @_ZdaPv(i8* [[TEST9_NEW]]) +} |