Files
clang-p2996/clang/test/CodeGenCXX/temporaries.cpp
Nikita Popov 158d72d728 [Clang] Set writable and dead_on_unwind attributes on sret arguments (#77116)
Set the writable and dead_on_unwind attributes for sret arguments. These
indicate that the argument points to writable memory (and it's legal to
introduce spurious writes to it on entry to the function) and that the
argument memory will not be used if the call unwinds.

This enables additional MemCpyOpt/DSE/LICM optimizations.
2024-01-11 09:46:54 +01:00

927 lines
28 KiB
C++

// 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 ptr @_ZGRN7PR162631rE_,
extern const int &s = reinterpret_cast<const int&>(n);
// CHECK: @_ZN7PR16263L1nE = internal constant i32 1234, align 4
// CHECK: @_ZN7PR162631sE ={{.*}} constant ptr @_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 {{.*}} @_ZGRN7PR162631aE_
extern const int &&t = ((B&&)C{}).n;
// CHECK: @_ZGRN7PR162631tE_ = internal global {{.*}} zeroinitializer,
// CHECK: @_ZN7PR162631tE ={{.*}} constant ptr {{.*}} @_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 ptr {{.*}} @_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 ptr @_ZGRN9BraceInit1xE_
}
namespace RefTempSubobject {
struct SelfReferential {
int *p = ints;
int ints[3] = {1, 2, 3};
};
// CHECK: @_ZGRN16RefTempSubobject2srE_ = internal global { ptr, [3 x i32] } { {{.*}} getelementptr {{.*}} @_ZGRN16RefTempSubobject2srE_, {{.*}}, [3 x i32] [i32 1, i32 2, i32 3] }
// CHECK: @_ZN16RefTempSubobject2srE = constant {{.*}} @_ZGRN16RefTempSubobject2srE_
constexpr const SelfReferential &sr = SelfReferential();
}
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 noundef i32 @_ZN6PR50771A1fEv
// CHECK: call void @_ZN6PR50771AD1Ev
: a1(A().f())
// CHECK: call void @_ZN6PR50771AC1Ev
// CHECK: call noundef 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 noundef i32 @_ZN3T121A1fEv(
// CHECK-NEXT: call noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @_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 noundef nonnull align 1 ptr @_ZN6PR66483zedENS_1BE
// NULL-VALID: call noundef align 1 ptr @_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.p0.i64
// CHECK: call void @_ZN6PR75561BD1Ev
B();
// CHECK: call void @llvm.memcpy.p0.p0.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(ptr {{[^,]*}} [[I]])
A i = (foo(), A());
// CHECK-NEXT: call void @_ZN7Elision4fooAEv(ptr dead_on_unwind writable sret([[A]]) align 8 [[T0]])
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[J]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[T0]])
A j = (fooA(), A());
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[T1]])
// CHECK-NEXT: call void @_ZN7Elision4fooAEv(ptr dead_on_unwind writable sret([[A]]) align 8 [[K]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[T1]])
A k = (A(), fooA());
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[K]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[J]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[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(ptr {{[^,]*}} [[I]])
// CHECK: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[I]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[X:%.*]])
A i = (c ? A() : x);
// CHECK: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[J]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[X]])
// CHECK: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[J]])
A j = (c ? x : A());
// CHECK: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[J]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[I]])
}
// CHECK: define{{.*}} void @_ZN7Elision5test2Ev(ptr dead_on_unwind noalias writable sret([[A]]) align 8
A test2() {
// CHECK: call void @_ZN7Elision3fooEv()
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[RET:%.*]])
// CHECK-NEXT: ret void
return (foo(), A());
}
// CHECK: define{{.*}} void @_ZN7Elision5test3EiNS_1AE(ptr dead_on_unwind noalias writable sret([[A]]) align 8
A test3(int v, A x) {
if (v < 5)
// CHECK: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[RET:%.*]])
// CHECK: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[RET]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[X:%.*]])
return (v < 0 ? A() : x);
else
// CHECK: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[RET]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[X]])
// CHECK: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[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(ptr {{[^,]*}} [[X]])
A x;
// CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]], ptr [[XS]], i64 0, i64 0
// CHECK-NEXT: call void @_ZN7Elision1AC1Ev(ptr {{[^,]*}} [[XS0]])
// CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [[A]], ptr [[XS0]], i64 1
// CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[XS1]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[X]])
A xs[] = { A(), x };
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [2 x [[A]]], ptr [[XS]], i32 0, i32 0
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[BEGIN]], i64 2
// CHECK-NEXT: br label
// CHECK: [[AFTER:%.*]] = phi ptr
// CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], ptr [[AFTER]], i64 -1
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[CUR]])
// CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[T0]],
// CHECK: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[X]])
}
// CHECK: define{{.*}} void @_ZN7Elision5test5Ev(ptr dead_on_unwind noalias writable sret([[A]]) align 8
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(ptr {{[^,]*}} [[BT0]])
// CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], ptr [[BT0]], i32 0, i32 0
// CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[AT0]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[AM]])
// CHECK-NEXT: call void @_ZN7Elision5takeAENS_1AE(ptr noundef [[AT0]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[AT0]])
// CHECK-NEXT: call void @_ZN7Elision1BD1Ev(ptr {{[^,]*}} [[BT0]])
takeA(B().a);
// CHECK-NEXT: call void @_ZN7Elision1BC1Ev(ptr {{[^,]*}} [[BT1]])
// CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], ptr [[BT1]], i32 0, i32 0
// CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[X]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[AM]])
// CHECK-NEXT: call void @_ZN7Elision1BD1Ev(ptr {{[^,]*}} [[BT1]])
A x = B().a;
// CHECK-NEXT: call void @_ZN7Elision1BC1Ev(ptr {{[^,]*}} [[BT2]])
// CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], ptr [[BT2]], i32 0, i32 0
// CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_(ptr {{[^,]*}} [[RET:%.*]], ptr noundef {{(nonnull )?}}align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[AM]])
// CHECK-NEXT: call void @_ZN7Elision1BD1Ev(ptr {{[^,]*}} [[BT2]])
return B().a;
// CHECK: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[X]])
}
// Reduced from webkit.
// CHECK: define{{.*}} void @_ZN7Elision5test6EPKNS_1CE(ptr
struct C { operator A() const; };
void test6(const C *x) {
// CHECK: [[T0:%.*]] = alloca [[A]], align 8
// CHECK: [[X:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv(ptr dead_on_unwind writable sret([[A]]) align 8 [[T0]], ptr {{[^,]*}} [[X]])
// CHECK-NEXT: call void @_ZNK7Elision1A3fooEv(ptr {{[^,]*}} [[T0]])
// CHECK-NEXT: call void @_ZN7Elision1AD1Ev(ptr {{[^,]*}} [[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, ptr [[LCONS]]
// CHECK-NEXT: store i1 false, ptr [[RCONS]]
// CHECK-NEXT: br i1
// CHECK: call void @_ZN6PR86231AC1Ei(ptr {{[^,]*}} [[TMP]], i32 noundef 2)
// CHECK-NEXT: store i1 true, ptr [[LCONS]]
// CHECK-NEXT: br label
// CHECK: call void @_ZN6PR86231AC1Ei(ptr {{[^,]*}} [[TMP]], i32 noundef 3)
// CHECK-NEXT: store i1 true, ptr [[RCONS]]
// CHECK-NEXT: br label
// CHECK: load i1, ptr [[RCONS]]
// CHECK-NEXT: br i1
// CHECK: call void @_ZN6PR86231AD1Ev(ptr {{[^,]*}} [[TMP]])
// CHECK-NEXT: br label
// CHECK: load i1, ptr [[LCONS]]
// CHECK-NEXT: br i1
// CHECK: call void @_ZN6PR86231AD1Ev(ptr {{[^,]*}} [[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:%.*]]], ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[BEGIN]], i64 3
// CHECK-NEXT: br label
// CHECK: [[PHI:%.*]] = phi
// CHECK-NEXT: [[ELEM:%.*]] = getelementptr inbounds [[A]], ptr [[PHI]], i64 -1
// CHECK-NEXT: call void @_ZN7PR113651AD1Ev(ptr {{[^,]*}} [[ELEM]])
// CHECK-NEXT: icmp eq ptr [[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({{.*}} @_ZN15BindToSubobject1AD1Ev, ptr @_ZGRN15BindToSubobject1aE_, ptr @__dso_handle)
// CHECK: store ptr @_ZGRN15BindToSubobject1aE_, ptr @_ZN15BindToSubobject1aE, align 8
int &&a = A().a;
// CHECK: call void @_ZN15BindToSubobject1fEv()
// CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1bE_)
// CHECK: call i32 @__cxa_atexit({{.*}} @_ZN15BindToSubobject1AD1Ev, ptr @_ZGRN15BindToSubobject1bE_, ptr @__dso_handle)
// CHECK: store ptr @_ZGRN15BindToSubobject1bE_, ptr @_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({{.*}} @_ZN15BindToSubobject1AD1Ev, ptr @_ZGRN15BindToSubobject1cE_, ptr @__dso_handle)
// CHECK: call {{.*}} @_ZN15BindToSubobject1hE
// CHECK: getelementptr
// CHECK: store ptr {{.*}}, ptr @_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({{.*}} @_ZN15BindToSubobject1BD1Ev, ptr @_ZGRN15BindToSubobject1dE_, ptr @__dso_handle)
// CHECK: call {{.*}} @_ZN15BindToSubobject1hE
// CHECK: getelementptr {{.*}} getelementptr
// CHECK: store ptr {{.*}}, ptr @_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 {{.*}}, ptr @_ZGRN8Bitfield1rE_
// CHECK: call void @_ZN8Bitfield1SD1
// CHECK: store ptr @_ZGRN8Bitfield1rE_, ptr @_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 {{.*}}, ptr @_ZGRN6Vector1rE_
// CHECK: store ptr @_ZGRN6Vector1rE_, ptr @_ZN6Vector1rE,
int &&r = S().v[1];
// CHECK: alloca
// CHECK: extractelement
// CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1sE_
// CHECK: store ptr @_ZGRN6Vector1sE_, ptr @_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]], {{.*}} @[[TEMPE:_ZGRN17MultipleExtension2e1E.*]],
// 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]], ptr @_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]], {{.*}} @[[E:_ZN17MultipleExtension2e2E]]
// 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]], ptr %[[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 noundef 1
// CHECK-NOT: @_ZN11ArrayAccess1AD
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 noundef 2
// CHECK-NOT: @_ZN11ArrayAccess1AD
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 noundef 3
// CHECK-NOT: @_ZN11ArrayAccess1AD
A &&a = T{1, 2, 3}[1];
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 noundef 4
// CHECK-NOT: @_ZN11ArrayAccess1AD
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 noundef 5
// CHECK-NOT: @_ZN11ArrayAccess1AD
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 noundef 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 noundef 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, ptr %[[CLEANUP_B:.*]],
// CHECK: store i1 false, ptr %[[CLEANUP_C:.*]],
// CHECK: br i1
//
// CHECK: call {{.*}} @_ZN11Conditional1BC1Ev(
// CHECK: store i1 true, ptr %[[CLEANUP_B]],
// CHECK: br label
//
// CHECK: call {{.*}} @_ZN11Conditional1CC1Ev(
// CHECK: store i1 true, ptr %[[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, ptr %[[CLEANUP_B:.*]],
// CHECK: store i1 false, ptr %[[CLEANUP_C:.*]],
// CHECK: br i1
//
// CHECK: call {{.*}} @_ZN11Conditional1BC1Ev(
// CHECK: store i1 true, ptr %[[CLEANUP_B]],
// CHECK: br label
//
// CHECK: call {{.*}} @_ZN11Conditional1CC1Ev(
// CHECK: store i1 true, ptr %[[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, ptr @_ZGRN11Conditional1rE_,
// CHECK: br label
//
// CHECK: call {{.*}} @_ZN11Conditional1CC1Ev({{.*}} @_ZGRN11Conditional1rE0_)
// CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN11Conditional1CD1Ev, ptr @_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