Files
clang-p2996/clang/test/CodeGenCXX/rvalue-references.cpp
Hal Finkel a2347baaec Mark C++ reference parameters as dereferenceable
Because references must be initialized using some evaluated expression, they
must point to something, and a callee can assume the reference parameter is
dereferenceable. Taking advantage of a new attribute just added to LLVM, mark
them as such.

Because dereferenceability in addrspace(0) implies nonnull in the backend, we
don't need both attributes. However, we need to know the size of the object to
use the dereferenceable attribute, so for incomplete types we still emit only
nonnull.

llvm-svn: 213386
2014-07-18 15:52:10 +00:00

112 lines
2.6 KiB
C++

// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
struct Spacer { int x; };
struct A { double array[2]; };
struct B : Spacer, A { };
B &getB();
// CHECK-LABEL: define dereferenceable({{[0-9]+}}) %struct.A* @_Z4getAv()
// CHECK: call dereferenceable({{[0-9]+}}) %struct.B* @_Z4getBv()
// CHECK-NEXT: bitcast %struct.B*
// CHECK-NEXT: getelementptr inbounds i8*
// CHECK-NEXT: bitcast i8* {{.*}} to %struct.A*
// CHECK-NEXT: ret %struct.A*
A &&getA() { return static_cast<A&&>(getB()); }
int &getIntLValue();
int &&getIntXValue();
int getIntPRValue();
// CHECK-LABEL: define dereferenceable({{[0-9]+}}) i32* @_Z2f0v()
// CHECK: call dereferenceable({{[0-9]+}}) i32* @_Z12getIntLValuev()
// CHECK-NEXT: ret i32*
int &&f0() { return static_cast<int&&>(getIntLValue()); }
// CHECK-LABEL: define dereferenceable({{[0-9]+}}) i32* @_Z2f1v()
// CHECK: call dereferenceable({{[0-9]+}}) i32* @_Z12getIntXValuev()
// CHECK-NEXT: ret i32*
int &&f1() { return static_cast<int&&>(getIntXValue()); }
// CHECK-LABEL: define dereferenceable({{[0-9]+}}) i32* @_Z2f2v
// CHECK: call i32 @_Z13getIntPRValuev()
// CHECK-NEXT: store i32 {{.*}}, i32*
// CHECK-NEXT: ret i32*
int &&f2() { return static_cast<int&&>(getIntPRValue()); }
bool ok;
class C
{
int* state_;
C(const C&) = delete;
C& operator=(const C&) = delete;
public:
C(int state) : state_(new int(state)) { }
C(C&& a) {
state_ = a.state_;
a.state_ = 0;
}
~C() {
delete state_;
state_ = 0;
}
};
C test();
// CHECK-LABEL: define void @_Z15elide_copy_initv
void elide_copy_init() {
ok = false;
// CHECK: call void @_Z4testv
C a = test();
// CHECK-NEXT: call void @_ZN1CD1Ev
// CHECK-NEXT: ret void
}
// CHECK-LABEL: define void @_Z16test_move_returnv
C test_move_return() {
// CHECK: call void @_ZN1CC1Ei
C a1(3);
// CHECK: call void @_ZN1CC1Ei
C a2(4);
if (ok)
// CHECK: call void @_ZN1CC1EOS_
return a1;
// CHECK: call void @_ZN1CC1EOS_
return a2;
// CHECK: call void @_ZN1CD1Ev
// CHECK: call void @_ZN1CD1Ev
//CHECK: ret void
}
// PR10800: don't crash
namespace test1 {
int &&move(int&);
struct A { A(int); };
struct B {
A a;
B(int i);
};
// CHECK-LABEL: define void @_ZN5test11BC2Ei(
// CHECK: [[T0:%.*]] = call dereferenceable({{[0-9]+}}) i32* @_ZN5test14moveERi(
// CHECK-NEXT: [[T1:%.*]] = load i32* [[T0]]
// CHECK-NEXT: call void @_ZN5test11AC1Ei({{.*}}, i32 [[T1]])
// CHECK-NEXT: ret void
B::B(int i) : a(move(i)) {}
}
// PR11009
struct MoveConvertible {
operator int&& () const;
};
void moveConstruct() {
(void)(int)MoveConvertible();
}