| // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 | FileCheck %s -check-prefixes=CHECK,NULL-INVALID,CHECK-CXX11 |
| // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++17 | FileCheck %s -check-prefixes=CHECK,NULL-INVALID,CHECK-CXX17 |
| // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 -fno-delete-null-pointer-checks | FileCheck %s -check-prefixes=CHECK,NULL-VALID,CHECK-CXX11 |
| |
| namespace PR16263 { |
| const unsigned int n = 1234; |
| extern const int &r = (const int&)n; |
| // CHECK: @_ZGRN7PR162631rE_ = internal constant i32 1234, |
| // CHECK: @_ZN7PR162631rE = constant i32* @_ZGRN7PR162631rE_, |
| |
| extern const int &s = reinterpret_cast<const int&>(n); |
| // CHECK: @_ZN7PR16263L1nE = internal constant i32 1234, align 4 |
| // CHECK: @_ZN7PR162631sE = constant i32* @_ZN7PR16263L1nE, align 8 |
| |
| struct A { int n; }; |
| struct B { int n; }; |
| struct C : A, B {}; |
| extern const A &&a = (A&&)(A&&)(C&&)(C{}); |
| // CHECK: @_ZGRN7PR162631aE_ = internal global {{.*}} zeroinitializer, |
| // CHECK: @_ZN7PR162631aE = constant {{.*}} bitcast ({{.*}}* @_ZGRN7PR162631aE_ to |
| |
| extern const int &&t = ((B&&)C{}).n; |
| // CHECK: @_ZGRN7PR162631tE_ = internal global {{.*}} zeroinitializer, |
| // CHECK: @_ZN7PR162631tE = constant i32* {{.*}}* @_ZGRN7PR162631tE_ {{.*}} 4 |
| |
| struct D { double d; C c; }; |
| extern const int &&u = (123, static_cast<B&&>(0, ((D&&)D{}).*&D::c).n); |
| // CHECK: @_ZGRN7PR162631uE_ = internal global {{.*}} zeroinitializer |
| // CHECK: @_ZN7PR162631uE = constant i32* {{.*}} @_ZGRN7PR162631uE_ {{.*}} 12 |
| } |
| |
| namespace PR20227 { |
| struct A { ~A(); }; |
| struct B { virtual ~B(); }; |
| struct C : B {}; |
| |
| A &&a = dynamic_cast<A&&>(A{}); |
| // CHECK: @_ZGRN7PR202271aE_ = internal global |
| |
| B &&b = dynamic_cast<C&&>(dynamic_cast<B&&>(C{})); |
| // CHECK: @_ZGRN7PR202271bE_ = internal global |
| |
| B &&c = static_cast<C&&>(static_cast<B&&>(C{})); |
| // CHECK: @_ZGRN7PR202271cE_ = internal global |
| } |
| |
| namespace BraceInit { |
| typedef const int &CIR; |
| CIR x = CIR{3}; |
| // CHECK-CXX11: @_ZGRN9BraceInit1xE_ = internal constant i32 3 |
| // FIXME: This should still be emitted as 'constant' in C++17. |
| // CHECK-CXX17: @_ZGRN9BraceInit1xE_ = internal global i32 3 |
| // CHECK: @_ZN9BraceInit1xE = constant i32* @_ZGRN9BraceInit1xE_ |
| } |
| |
| struct A { |
| A(); |
| ~A(); |
| void f(); |
| }; |
| |
| void f1() { |
| // CHECK: call void @_ZN1AC1Ev |
| // CHECK: call void @_ZN1AD1Ev |
| (void)A(); |
| |
| // CHECK: call void @_ZN1AC1Ev |
| // CHECK: call void @_ZN1AD1Ev |
| A().f(); |
| } |
| |
| // Function calls |
| struct B { |
| B(); |
| ~B(); |
| }; |
| |
| B g(); |
| |
| void f2() { |
| // CHECK-NOT: call void @_ZN1BC1Ev |
| // CHECK: call void @_ZN1BD1Ev |
| (void)g(); |
| } |
| |
| // Member function calls |
| struct C { |
| C(); |
| ~C(); |
| |
| C f(); |
| }; |
| |
| void f3() { |
| // CHECK: call void @_ZN1CC1Ev |
| // CHECK: call void @_ZN1CD1Ev |
| // CHECK: call void @_ZN1CD1Ev |
| C().f(); |
| } |
| |
| // Function call operator |
| struct D { |
| D(); |
| ~D(); |
| |
| D operator()(); |
| }; |
| |
| void f4() { |
| // CHECK: call void @_ZN1DC1Ev |
| // CHECK: call void @_ZN1DD1Ev |
| // CHECK: call void @_ZN1DD1Ev |
| D()(); |
| } |
| |
| // Overloaded operators |
| struct E { |
| E(); |
| ~E(); |
| E operator+(const E&); |
| E operator!(); |
| }; |
| |
| void f5() { |
| // CHECK: call void @_ZN1EC1Ev |
| // CHECK: call void @_ZN1EC1Ev |
| // CHECK: call void @_ZN1ED1Ev |
| // CHECK: call void @_ZN1ED1Ev |
| // CHECK: call void @_ZN1ED1Ev |
| E() + E(); |
| |
| // CHECK: call void @_ZN1EC1Ev |
| // CHECK: call void @_ZN1ED1Ev |
| // CHECK: call void @_ZN1ED1Ev |
| !E(); |
| } |
| |
| struct F { |
| F(); |
| ~F(); |
| F& f(); |
| }; |
| |
| void f6() { |
| // CHECK: call void @_ZN1FC1Ev |
| // CHECK: call void @_ZN1FD1Ev |
| F().f(); |
| } |
| |
| struct G { |
| G(); |
| G(A); |
| ~G(); |
| operator A(); |
| }; |
| |
| void a(const A&); |
| |
| void f7() { |
| // CHECK: call void @_ZN1AC1Ev |
| // CHECK: call void @_Z1aRK1A |
| // CHECK: call void @_ZN1AD1Ev |
| a(A()); |
| |
| // CHECK: call void @_ZN1GC1Ev |
| // CHECK: call void @_ZN1Gcv1AEv |
| // CHECK: call void @_Z1aRK1A |
| // CHECK: call void @_ZN1AD1Ev |
| // CHECK: call void @_ZN1GD1Ev |
| a(G()); |
| } |
| |
| namespace PR5077 { |
| |
| struct A { |
| A(); |
| ~A(); |
| int f(); |
| }; |
| |
| void f(); |
| int g(const A&); |
| |
| struct B { |
| int a1; |
| int a2; |
| B(); |
| ~B(); |
| }; |
| |
| B::B() |
| // CHECK: call void @_ZN6PR50771AC1Ev |
| // CHECK: call i32 @_ZN6PR50771A1fEv |
| // CHECK: call void @_ZN6PR50771AD1Ev |
| : a1(A().f()) |
| // CHECK: call void @_ZN6PR50771AC1Ev |
| // CHECK: call i32 @_ZN6PR50771gERKNS_1AE |
| // CHECK: call void @_ZN6PR50771AD1Ev |
| , a2(g(A())) |
| { |
| // CHECK: call void @_ZN6PR50771fEv |
| f(); |
| } |
| |
| } |
| |
| A f8() { |
| // CHECK: call void @_ZN1AC1Ev |
| // CHECK-NOT: call void @_ZN1AD1Ev |
| return A(); |
| // CHECK: ret void |
| } |
| |
| struct H { |
| H(); |
| ~H(); |
| H(const H&); |
| }; |
| |
| void f9(H h) { |
| // CHECK: call void @_ZN1HC1Ev |
| // CHECK: call void @_Z2f91H |
| // CHECK: call void @_ZN1HD1Ev |
| f9(H()); |
| |
| // CHECK: call void @_ZN1HC1ERKS_ |
| // CHECK: call void @_Z2f91H |
| // CHECK: call void @_ZN1HD1Ev |
| f9(h); |
| } |
| |
| void f10(const H&); |
| |
| void f11(H h) { |
| // CHECK: call void @_ZN1HC1Ev |
| // CHECK: call void @_Z3f10RK1H |
| // CHECK: call void @_ZN1HD1Ev |
| f10(H()); |
| |
| // CHECK: call void @_Z3f10RK1H |
| // CHECK-NOT: call void @_ZN1HD1Ev |
| // CHECK: ret void |
| f10(h); |
| } |
| |
| // PR5808 |
| struct I { |
| I(const char *); |
| ~I(); |
| }; |
| |
| // CHECK: _Z3f12v |
| I f12() { |
| // CHECK: call void @_ZN1IC1EPKc |
| // CHECK-NOT: call void @_ZN1ID1Ev |
| // CHECK: ret void |
| return "Hello"; |
| } |
| |
| // PR5867 |
| namespace PR5867 { |
| struct S { |
| S(); |
| S(const S &); |
| ~S(); |
| }; |
| |
| void f(S, int); |
| // CHECK-LABEL: define void @_ZN6PR58671gEv |
| void g() { |
| // CHECK: call void @_ZN6PR58671SC1Ev |
| // CHECK-NEXT: call void @_ZN6PR58671fENS_1SEi |
| // CHECK-NEXT: call void @_ZN6PR58671SD1Ev |
| // CHECK-NEXT: ret void |
| (f)(S(), 0); |
| } |
| |
| // CHECK-LABEL: define linkonce_odr void @_ZN6PR58672g2IiEEvT_ |
| template<typename T> |
| void g2(T) { |
| // CHECK: call void @_ZN6PR58671SC1Ev |
| // CHECK-NEXT: call void @_ZN6PR58671fENS_1SEi |
| // CHECK-NEXT: call void @_ZN6PR58671SD1Ev |
| // CHECK-NEXT: ret void |
| (f)(S(), 0); |
| } |
| |
| void h() { |
| g2(17); |
| } |
| } |
| |
| // PR6199 |
| namespace PR6199 { |
| struct A { ~A(); }; |
| |
| struct B { operator A(); }; |
| |
| // CHECK-LABEL: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_ |
| template<typename T> A f2(T) { |
| B b; |
| // CHECK: call void @_ZN6PR61991BcvNS_1AEEv |
| // CHECK-NEXT: ret void |
| return b; |
| } |
| |
| template A f2<int>(int); |
| |
| } |
| |
| namespace T12 { |
| |
| struct A { |
| A(); |
| ~A(); |
| int f(); |
| }; |
| |
| int& f(int); |
| |
| // CHECK-LABEL: define void @_ZN3T121gEv |
| void g() { |
| // CHECK: call void @_ZN3T121AC1Ev |
| // CHECK-NEXT: call i32 @_ZN3T121A1fEv( |
| // CHECK-NEXT: call dereferenceable({{[0-9]+}}) i32* @_ZN3T121fEi( |
| // CHECK-NEXT: call void @_ZN3T121AD1Ev( |
| int& i = f(A().f()); |
| } |
| |
| } |
| |
| namespace PR6648 { |
| struct B { |
| ~B(); |
| }; |
| B foo; |
| struct D; |
| D& zed(B); |
| void foobar() { |
| // NULL-INVALID: call nonnull %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE |
| // NULL-VALID: call %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE |
| zed(foo); |
| } |
| } |
| |
| namespace UserConvertToValue { |
| struct X { |
| X(int); |
| X(const X&); |
| ~X(); |
| }; |
| |
| void f(X); |
| |
| // CHECK: void @_ZN18UserConvertToValue1gEv() |
| void g() { |
| // CHECK: call void @_ZN18UserConvertToValue1XC1Ei |
| // CHECK: call void @_ZN18UserConvertToValue1fENS_1XE |
| // CHECK: call void @_ZN18UserConvertToValue1XD1Ev |
| // CHECK: ret void |
| f(1); |
| } |
| } |
| |
| namespace PR7556 { |
| struct A { ~A(); }; |
| struct B { int i; ~B(); }; |
| struct C { int C::*pm; ~C(); }; |
| // CHECK-LABEL: define void @_ZN6PR75563fooEv() |
| void foo() { |
| // CHECK: call void @_ZN6PR75561AD1Ev |
| A(); |
| // CHECK: call void @llvm.memset.p0i8.i64 |
| // CHECK: call void @_ZN6PR75561BD1Ev |
| B(); |
| // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 |
| // CHECK: call void @_ZN6PR75561CD1Ev |
| C(); |
| // CHECK-NEXT: ret void |
| } |
| } |
| |
| namespace Elision { |
| struct A { |
| A(); A(const A &); ~A(); |
| void *p; |
| void foo() const; |
| }; |
| |
| void foo(); |
| A fooA(); |
| void takeA(A a); |
| |
| // CHECK-LABEL: define void @_ZN7Elision5test0Ev() |
| void test0() { |
| // CHECK: [[I:%.*]] = alloca [[A:%.*]], align 8 |
| // CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[T0:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[K:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[T1:%.*]] = alloca [[A]], align 8 |
| |
| // CHECK-NEXT: call void @_ZN7Elision3fooEv() |
| // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[I]]) |
| A i = (foo(), A()); |
| |
| // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[T0]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[J]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) |
| A j = (fooA(), A()); |
| |
| // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[T1]]) |
| // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[K]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T1]]) |
| A k = (A(), fooA()); |
| |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[K]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[J]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]]) |
| } |
| |
| |
| // CHECK-LABEL: define void @_ZN7Elision5test1EbNS_1AE( |
| void test1(bool c, A x) { |
| // CHECK: [[I:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8 |
| |
| // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[I]]) |
| // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[I]], [[A]]* dereferenceable({{[0-9]+}}) [[X:%.*]]) |
| A i = (c ? A() : x); |
| |
| // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[J]], [[A]]* dereferenceable({{[0-9]+}}) [[X]]) |
| // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[J]]) |
| A j = (c ? x : A()); |
| |
| // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[J]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]]) |
| } |
| |
| // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret |
| A test2() { |
| // CHECK: call void @_ZN7Elision3fooEv() |
| // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) |
| // CHECK-NEXT: ret void |
| return (foo(), A()); |
| } |
| |
| // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret |
| A test3(int v, A x) { |
| if (v < 5) |
| // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) |
| // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET]], [[A]]* dereferenceable({{[0-9]+}}) [[X:%.*]]) |
| return (v < 0 ? A() : x); |
| else |
| // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET]], [[A]]* dereferenceable({{[0-9]+}}) [[X]]) |
| // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET]]) |
| return (v > 10 ? x : A()); |
| |
| // CHECK: ret void |
| } |
| |
| // CHECK-LABEL: define void @_ZN7Elision5test4Ev() |
| void test4() { |
| // CHECK: [[X:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16 |
| |
| // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[X]]) |
| A x; |
| |
| // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]], [2 x [[A]]]* [[XS]], i64 0, i64 0 |
| // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[XS0]]) |
| // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[XS0]], i64 1 |
| // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[XS1]], [[A]]* dereferenceable({{[0-9]+}}) [[X]]) |
| A xs[] = { A(), x }; |
| |
| // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [2 x [[A]]], [2 x [[A]]]* [[XS]], i32 0, i32 0 |
| // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], [[A]]* [[BEGIN]], i64 2 |
| // CHECK-NEXT: br label |
| // CHECK: [[AFTER:%.*]] = phi [[A]]* |
| // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], [[A]]* [[AFTER]], i64 -1 |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[CUR]]) |
| // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] |
| // CHECK-NEXT: br i1 [[T0]], |
| |
| // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]]) |
| } |
| |
| // rdar://problem/8433352 |
| // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret |
| struct B { A a; B(); }; |
| A test5() { |
| // CHECK: [[AT0:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[BT0:%.*]] = alloca [[B:%.*]], align 8 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[A]], align 8 |
| // CHECK-NEXT: [[BT1:%.*]] = alloca [[B]], align 8 |
| // CHECK-NEXT: [[BT2:%.*]] = alloca [[B]], align 8 |
| |
| // CHECK: call void @_ZN7Elision1BC1Ev([[B]]* [[BT0]]) |
| // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], [[B]]* [[BT0]], i32 0, i32 0 |
| // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[AT0]], [[A]]* dereferenceable({{[0-9]+}}) [[AM]]) |
| // CHECK-NEXT: call void @_ZN7Elision5takeAENS_1AE([[A]]* [[AT0]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[AT0]]) |
| // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT0]]) |
| takeA(B().a); |
| |
| // CHECK-NEXT: call void @_ZN7Elision1BC1Ev([[B]]* [[BT1]]) |
| // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], [[B]]* [[BT1]], i32 0, i32 0 |
| // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[X]], [[A]]* dereferenceable({{[0-9]+}}) [[AM]]) |
| // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT1]]) |
| A x = B().a; |
| |
| // CHECK-NEXT: call void @_ZN7Elision1BC1Ev([[B]]* [[BT2]]) |
| // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], [[B]]* [[BT2]], i32 0, i32 0 |
| // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET:%.*]], [[A]]* dereferenceable({{[0-9]+}}) [[AM]]) |
| // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT2]]) |
| return B().a; |
| |
| // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]]) |
| } |
| |
| // Reduced from webkit. |
| // CHECK: define void @_ZN7Elision5test6EPKNS_1CE([[C:%.*]]* |
| struct C { operator A() const; }; |
| void test6(const C *x) { |
| // CHECK: [[T0:%.*]] = alloca [[A]], align 8 |
| // CHECK: [[X:%.*]] = load [[C]]*, [[C]]** {{%.*}}, align 8 |
| // CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv([[A]]* sret [[T0]], [[C]]* [[X]]) |
| // CHECK-NEXT: call void @_ZNK7Elision1A3fooEv([[A]]* [[T0]]) |
| // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) |
| // CHECK-NEXT: ret void |
| A(*x).foo(); |
| } |
| } |
| |
| namespace PR8623 { |
| struct A { A(int); ~A(); }; |
| |
| // CHECK-LABEL: define void @_ZN6PR86233fooEb( |
| void foo(bool b) { |
| // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 |
| // CHECK-NEXT: [[LCONS:%.*]] = alloca i1 |
| // CHECK-NEXT: [[RCONS:%.*]] = alloca i1 |
| // CHECK: store i1 false, i1* [[LCONS]] |
| // CHECK-NEXT: store i1 false, i1* [[RCONS]] |
| // CHECK-NEXT: br i1 |
| // CHECK: call void @_ZN6PR86231AC1Ei([[A]]* [[TMP]], i32 2) |
| // CHECK-NEXT: store i1 true, i1* [[LCONS]] |
| // CHECK-NEXT: br label |
| // CHECK: call void @_ZN6PR86231AC1Ei([[A]]* [[TMP]], i32 3) |
| // CHECK-NEXT: store i1 true, i1* [[RCONS]] |
| // CHECK-NEXT: br label |
| // CHECK: load i1, i1* [[RCONS]] |
| // CHECK-NEXT: br i1 |
| // CHECK: call void @_ZN6PR86231AD1Ev([[A]]* [[TMP]]) |
| // CHECK-NEXT: br label |
| // CHECK: load i1, i1* [[LCONS]] |
| // CHECK-NEXT: br i1 |
| // CHECK: call void @_ZN6PR86231AD1Ev([[A]]* [[TMP]]) |
| // CHECK-NEXT: br label |
| // CHECK: ret void |
| b ? A(2) : A(3); |
| } |
| } |
| |
| namespace PR11365 { |
| struct A { A(); ~A(); }; |
| |
| // CHECK-LABEL: define void @_ZN7PR113653fooEv( |
| void foo() { |
| // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [[A:%.*]]], [3 x [[A:%.*]]]* {{.*}}, i32 0, i32 0 |
| // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], [[A]]* [[BEGIN]], i64 3 |
| // CHECK-NEXT: br label |
| |
| // CHECK: [[PHI:%.*]] = phi |
| // CHECK-NEXT: [[ELEM:%.*]] = getelementptr inbounds [[A]], [[A]]* [[PHI]], i64 -1 |
| // CHECK-NEXT: call void @_ZN7PR113651AD1Ev([[A]]* [[ELEM]]) |
| // CHECK-NEXT: icmp eq [[A]]* [[ELEM]], [[BEGIN]] |
| // CHECK-NEXT: br i1 |
| (void) (A [3]) {}; |
| } |
| } |
| |
| namespace AssignmentOp { |
| struct A { ~A(); }; |
| struct B { A operator=(const B&); }; |
| struct C : B { B b1, b2; }; |
| // CHECK-LABEL: define void @_ZN12AssignmentOp1fE |
| void f(C &c1, const C &c2) { |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1CaSERKS0_( |
| c1 = c2; |
| } |
| |
| // Ensure that each 'A' temporary is destroyed before the next subobject is |
| // copied. |
| // CHECK: define {{.*}} @_ZN12AssignmentOp1CaSERKS0_( |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev( |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev( |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS |
| // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev( |
| } |
| |
| namespace BindToSubobject { |
| struct A { |
| A(); |
| ~A(); |
| int a; |
| }; |
| |
| void f(), g(); |
| |
| // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1aE_) |
| // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1aE_ to i8*), i8* @__dso_handle) |
| // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1aE_, i32 0, i32 0), i32** @_ZN15BindToSubobject1aE, align 8 |
| int &&a = A().a; |
| |
| // CHECK: call void @_ZN15BindToSubobject1fEv() |
| // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1bE_) |
| // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1bE_ to i8*), i8* @__dso_handle) |
| // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1bE_, i32 0, i32 0), i32** @_ZN15BindToSubobject1bE, align 8 |
| int &&b = (f(), A().a); |
| |
| int A::*h(); |
| |
| // CHECK: call void @_ZN15BindToSubobject1fEv() |
| // CHECK: call void @_ZN15BindToSubobject1gEv() |
| // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE_) |
| // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE_ to i8*), i8* @__dso_handle) |
| // CHECK: call {{.*}} @_ZN15BindToSubobject1hE |
| // CHECK: getelementptr |
| // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8 |
| int &&c = (f(), (g(), A().*h())); |
| |
| struct B { |
| int padding; |
| A a; |
| }; |
| |
| // CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE_) |
| // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE_ to i8*), i8* @__dso_handle) |
| // CHECK: call {{.*}} @_ZN15BindToSubobject1hE |
| // CHECK: getelementptr {{.*}} getelementptr |
| // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8 |
| int &&d = (B().a).*h(); |
| } |
| |
| namespace Bitfield { |
| struct S { int a : 5; ~S(); }; |
| |
| // Do not lifetime extend the S() temporary here. |
| // CHECK: alloca |
| // CHECK: call {{.*}}memset |
| // CHECK: store i32 {{.*}}, i32* @_ZGRN8Bitfield1rE_ |
| // CHECK: call void @_ZN8Bitfield1SD1 |
| // CHECK: store i32* @_ZGRN8Bitfield1rE_, i32** @_ZN8Bitfield1rE, align 8 |
| int &&r = S().a; |
| } |
| |
| namespace Vector { |
| typedef __attribute__((vector_size(16))) int vi4a; |
| typedef __attribute__((ext_vector_type(4))) int vi4b; |
| struct S { |
| vi4a v; |
| vi4b w; |
| }; |
| // CHECK: alloca |
| // CHECK: extractelement |
| // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1rE_ |
| // CHECK: store i32* @_ZGRN6Vector1rE_, i32** @_ZN6Vector1rE, |
| int &&r = S().v[1]; |
| |
| // CHECK: alloca |
| // CHECK: extractelement |
| // CHECK: store i32 {{.*}}, i32* @_ZGRN6Vector1sE_ |
| // CHECK: store i32* @_ZGRN6Vector1sE_, i32** @_ZN6Vector1sE, |
| int &&s = S().w[1]; |
| // FIXME PR16204: The following code leads to an assertion in Sema. |
| //int &&s = S().w.y; |
| } |
| |
| namespace ImplicitTemporaryCleanup { |
| struct A { A(int); ~A(); }; |
| void g(); |
| |
| // CHECK-LABEL: define void @_ZN24ImplicitTemporaryCleanup1fEv( |
| void f() { |
| // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1AC1Ei( |
| A &&a = 0; |
| |
| // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1gEv( |
| g(); |
| |
| // CHECK: call {{.*}} @_ZN24ImplicitTemporaryCleanup1AD1Ev( |
| } |
| } |
| |
| namespace MultipleExtension { |
| struct A { A(); ~A(); }; |
| struct B { B(); ~B(); }; |
| struct C { C(); ~C(); }; |
| struct D { D(); ~D(); int n; C c; }; |
| struct E { const A &a; B b; const C &c; ~E(); }; |
| |
| E &&e1 = { A(), B(), D().c }; |
| |
| // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e1E.*]]) |
| // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]] |
| // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]], i32 0, i32 0) |
| |
| // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 1)) |
| |
| // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e1E.*]]) |
| // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]] |
| // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[TEMPE]], i32 0, i32 2) |
| // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[TEMPE]] |
| // CHECK: store {{.*}} @[[TEMPE]], %"struct.MultipleExtension::E"** @_ZN17MultipleExtension2e1E, align 8 |
| |
| E e2 = { A(), B(), D().c }; |
| |
| // CHECK: call void @_ZN17MultipleExtension1AC1Ev({{.*}} @[[TEMPA:_ZGRN17MultipleExtension2e2E.*]]) |
| // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1AD1Ev {{.*}} @[[TEMPA]] |
| // CHECK: store {{.*}} @[[TEMPA]], {{.*}} getelementptr inbounds ({{.*}} @[[E:_ZN17MultipleExtension2e2E]], i32 0, i32 0) |
| |
| // CHECK: call void @_ZN17MultipleExtension1BC1Ev({{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 1)) |
| |
| // CHECK: call void @_ZN17MultipleExtension1DC1Ev({{.*}} @[[TEMPD:_ZGRN17MultipleExtension2e2E.*]]) |
| // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1DD1Ev {{.*}} @[[TEMPD]] |
| // CHECK: store {{.*}} @[[TEMPD]], {{.*}} getelementptr inbounds ({{.*}} @[[E]], i32 0, i32 2) |
| // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN17MultipleExtension1ED1Ev {{.*}} @[[E]] |
| |
| |
| void g(); |
| // CHECK: define void @[[NS:_ZN17MultipleExtension]]1fEv( |
| void f() { |
| E &&e1 = { A(), B(), D().c }; |
| // CHECK: %[[TEMPE1_A:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1:.*]], i32 0, i32 0 |
| // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA1:.*]]) |
| // CHECK: store {{.*}} %[[TEMPA1]], {{.*}} %[[TEMPE1_A]] |
| // CHECK: %[[TEMPE1_B:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 1 |
| // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE1_B]]) |
| // CHECK: %[[TEMPE1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPE1]], i32 0, i32 2 |
| // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD1:.*]]) |
| // CHECK: %[[TEMPD1_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD1]], i32 0, i32 1 |
| // CHECK: store {{.*}} %[[TEMPD1_C]], {{.*}} %[[TEMPE1_C]] |
| // CHECK: store {{.*}} %[[TEMPE1]], {{.*}} %[[E1:.*]] |
| |
| g(); |
| // CHECK: call void @[[NS]]1gEv() |
| |
| E e2 = { A(), B(), D().c }; |
| // CHECK: %[[TEMPE2_A:.*]] = getelementptr inbounds {{.*}} %[[E2:.*]], i32 0, i32 0 |
| // CHECK: call void @[[NS]]1AC1Ev({{.*}} %[[TEMPA2:.*]]) |
| // CHECK: store {{.*}} %[[TEMPA2]], {{.*}} %[[TEMPE2_A]] |
| // CHECK: %[[TEMPE2_B:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 1 |
| // CHECK: call void @[[NS]]1BC1Ev({{.*}} %[[TEMPE2_B]]) |
| // CHECK: %[[TEMPE2_C:.*]] = getelementptr inbounds {{.*}} %[[E2]], i32 0, i32 2 |
| // CHECK: call void @[[NS]]1DC1Ev({{.*}} %[[TEMPD2:.*]]) |
| // CHECK: %[[TEMPD2_C:.*]] = getelementptr inbounds {{.*}} %[[TEMPD2]], i32 0, i32 1 |
| // CHECK: store {{.*}} %[[TEMPD2_C]], {{.*}}* %[[TEMPE2_C]] |
| |
| g(); |
| // CHECK: call void @[[NS]]1gEv() |
| |
| // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[E2]]) |
| // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD2]]) |
| // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA2]]) |
| // CHECK: call void @[[NS]]1ED1Ev({{.*}} %[[TEMPE1]]) |
| // CHECK: call void @[[NS]]1DD1Ev({{.*}} %[[TEMPD1]]) |
| // CHECK: call void @[[NS]]1AD1Ev({{.*}} %[[TEMPA1]]) |
| } |
| } |
| |
| namespace ArrayAccess { |
| struct A { A(int); ~A(); }; |
| void g(); |
| void f() { |
| using T = A[3]; |
| |
| // CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 1 |
| // CHECK-NOT: @_ZN11ArrayAccess1AD |
| // CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 2 |
| // CHECK-NOT: @_ZN11ArrayAccess1AD |
| // CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 3 |
| // CHECK-NOT: @_ZN11ArrayAccess1AD |
| A &&a = T{1, 2, 3}[1]; |
| |
| // CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 4 |
| // CHECK-NOT: @_ZN11ArrayAccess1AD |
| // CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 5 |
| // CHECK-NOT: @_ZN11ArrayAccess1AD |
| // CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 6 |
| // CHECK-NOT: @_ZN11ArrayAccess1AD |
| A &&b = 2[T{4, 5, 6}]; |
| |
| // CHECK: call void @_ZN11ArrayAccess1gEv( |
| g(); |
| |
| // CHECK: call void @_ZN11ArrayAccess1AD |
| // CHECK: call void @_ZN11ArrayAccess1AD |
| } |
| } |
| |
| namespace PR14130 { |
| struct S { S(int); }; |
| struct U { S &&s; }; |
| U v { { 0 } }; |
| // CHECK: call void @_ZN7PR141301SC1Ei({{.*}} @_ZGRN7PR141301vE_, i32 0) |
| // CHECK: store {{.*}} @_ZGRN7PR141301vE_, {{.*}} @_ZN7PR141301vE |
| } |
| |
| namespace Conditional { |
| struct A {}; |
| struct B : A { B(); ~B(); }; |
| struct C : A { C(); ~C(); }; |
| |
| void g(); |
| |
| // CHECK-LABEL: define {{.*}} @_ZN11Conditional1fEb( |
| void f(bool b) { |
| // CHECK: store i1 false, i1* %[[CLEANUP_B:.*]], |
| // CHECK: store i1 false, i1* %[[CLEANUP_C:.*]], |
| // CHECK: br i1 |
| // |
| // CHECK: call {{.*}} @_ZN11Conditional1BC1Ev( |
| // CHECK: store i1 true, i1* %[[CLEANUP_B]], |
| // CHECK: br label |
| // |
| // CHECK: call {{.*}} @_ZN11Conditional1CC1Ev( |
| // CHECK: store i1 true, i1* %[[CLEANUP_C]], |
| // CHECK: br label |
| A &&r = b ? static_cast<A&&>(B()) : static_cast<A&&>(C()); |
| |
| // CHECK: call {{.*}} @_ZN11Conditional1gEv( |
| g(); |
| |
| // CHECK: load {{.*}} %[[CLEANUP_C]] |
| // CHECK: br i1 |
| // CHECK: call {{.*}} @_ZN11Conditional1CD1Ev( |
| // CHECK: br label |
| |
| // CHECK: load {{.*}} %[[CLEANUP_B]] |
| // CHECK: br i1 |
| // CHECK: call {{.*}} @_ZN11Conditional1BD1Ev( |
| // CHECK: br label |
| } |
| |
| struct D { A &&a; }; |
| // CHECK-LABEL: define {{.*}} @_ZN11Conditional10f_indirectEb( |
| void f_indirect(bool b) { |
| // CHECK: store i1 false, i1* %[[CLEANUP_B:.*]], |
| // CHECK: store i1 false, i1* %[[CLEANUP_C:.*]], |
| // CHECK: br i1 |
| // |
| // CHECK: call {{.*}} @_ZN11Conditional1BC1Ev( |
| // CHECK: store i1 true, i1* %[[CLEANUP_B]], |
| // CHECK: br label |
| // |
| // CHECK: call {{.*}} @_ZN11Conditional1CC1Ev( |
| // CHECK: store i1 true, i1* %[[CLEANUP_C]], |
| // CHECK: br label |
| D d = b ? D{B()} : D{C()}; |
| |
| // In C++17, the expression D{...} directly initializes the 'd' object, so |
| // lifetime-extending the temporaries to the lifetime of the D object |
| // extends them past the call to g(). |
| // |
| // In C++14 and before, D is move-constructed from the result of the |
| // conditional expression, so no lifetime extension occurs. |
| |
| // CHECK-CXX17: call {{.*}} @_ZN11Conditional1gEv( |
| |
| // CHECK: load {{.*}} %[[CLEANUP_C]] |
| // CHECK: br i1 |
| // CHECK: call {{.*}} @_ZN11Conditional1CD1Ev( |
| // CHECK: br label |
| |
| // CHECK: load {{.*}} %[[CLEANUP_B]] |
| // CHECK: br i1 |
| // CHECK: call {{.*}} @_ZN11Conditional1BD1Ev( |
| // CHECK: br label |
| |
| // CHECK-CXX11: call {{.*}} @_ZN11Conditional1gEv( |
| g(); |
| } |
| |
| extern bool b; |
| // CHECK: load {{.*}} @_ZN11Conditional1b |
| // CHECK: br i1 |
| // |
| // CHECK: call {{.*}} @_ZN11Conditional1BC1Ev({{.*}} @_ZGRN11Conditional1rE_) |
| // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN11Conditional1BD1Ev {{.*}} @_ZGRN11Conditional1rE_, |
| // CHECK: br label |
| // |
| // CHECK: call {{.*}} @_ZN11Conditional1CC1Ev({{.*}} @_ZGRN11Conditional1rE0_) |
| // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN11Conditional1CD1Ev {{.*}} @_ZGRN11Conditional1rE0_, |
| // CHECK: br label |
| A &&r = b ? static_cast<A&&>(B()) : static_cast<A&&>(C()); |
| } |
| |
| #if __cplusplus >= 201703L |
| namespace PR42220 { |
| struct X { X(); ~X(); }; |
| struct A { X &&x; }; |
| struct B : A {}; |
| void g() noexcept; |
| // CHECK-CXX17-LABEL: define{{.*}} @_ZN7PR422201fEv( |
| void f() { |
| // CHECK-CXX17: call{{.*}} @_ZN7PR422201XC1Ev( |
| B &&b = {X()}; |
| // CHECK-CXX17-NOT: call{{.*}} @_ZN7PR422201XD1Ev( |
| // CHECK-CXX17: call{{.*}} @_ZN7PR422201gEv( |
| g(); |
| // CHECK-CXX17: call{{.*}} @_ZN7PR422201XD1Ev( |
| } |
| } |
| #endif |