blob: fdfa6781fe27474865e5a7eb49b869a72d04b084 [file] [log] [blame]
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -pedantic %s
// Test the c++0x-specific reference initialization rules, e.g., the
// rules for rvalue references.
template<typename T> T prvalue();
template<typename T> T&& xvalue();
template<typename T> T& lvalue();
struct Base { };
struct Derived : Base { };
struct HasArray {
int array[5];
};
int f(int);
template<typename T>
struct ConvertsTo {
operator T(); // expected-note 2{{candidate function}}
};
void test_rvalue_refs() {
// If the initializer expression...
// - is an xvalue, class prvalue, array prvalue or function lvalue
// and "cv1 T1" is reference-compatible with "cv2 T2", or
// xvalue case
Base&& base0 = xvalue<Base>();
Base&& base1 = xvalue<Derived>();
int&& int0 = xvalue<int>();
// class prvalue case
Base&& base2 = prvalue<Base>();
Base&& base3 = prvalue<Derived>();
// array prvalue case
int (&&array0)[5] = HasArray().array;
// function lvalue case
int (&&function0)(int) = f;
// - has a class type (i.e., T2 is a class type), where T1 is not
// reference-related to T2, and can be implicitly converted to
// an xvalue, class prvalue, or function lvalue of type "cv3
// T3", where "cv1 T1" is reference-compatible with "cv3 T3",
// xvalue
Base&& base4 = ConvertsTo<Base&&>();
Base&& base5 = ConvertsTo<Derived&&>();
int && int1 = ConvertsTo<int&&>();
// class prvalue
Base&& base6 = ConvertsTo<Base>();
Base&& base7 = ConvertsTo<Derived>();
// function lvalue
int (&&function1)(int) = ConvertsTo<int(&)(int)>();
// In the second case, if the reference is an rvalue reference and
// the second standard conversion sequence of the user-defined
// conversion sequence includes an lvalue-to-rvalue conversion, the
// program is ill-formed.
int &&int2 = ConvertsTo<int&>(); // expected-error{{no viable conversion from 'ConvertsTo<int &>' to 'int'}}
int &&int3 = ConvertsTo<float&>(); // expected-error{{no viable conversion from 'ConvertsTo<float &>' to 'int'}}
}
class NonCopyable {
NonCopyable(const NonCopyable&);
};
class NonCopyableDerived : public NonCopyable {
NonCopyableDerived(const NonCopyableDerived&);
};
// Make sure we get direct bindings with no copies.
void test_direct_binding() {
NonCopyable &&nc0 = prvalue<NonCopyable>();
NonCopyable &&nc1 = prvalue<NonCopyableDerived>();
NonCopyable &&nc2 = xvalue<NonCopyable>();
NonCopyable &&nc3 = xvalue<NonCopyableDerived>();
const NonCopyable &nc4 = prvalue<NonCopyable>();
const NonCopyable &nc5 = prvalue<NonCopyableDerived>();
const NonCopyable &nc6 = xvalue<NonCopyable>();
const NonCopyable &nc7 = xvalue<NonCopyableDerived>();
NonCopyable &&nc8 = ConvertsTo<NonCopyable&&>();
NonCopyable &&nc9 = ConvertsTo<NonCopyableDerived&&>();
const NonCopyable &nc10 = ConvertsTo<NonCopyable&&>();
const NonCopyable &nc11 = ConvertsTo<NonCopyableDerived&&>();
}
namespace std_example_1 {
double d = 2.0;
double& rd = d;
const double& rcd = d;
struct A { };
struct B : A {
operator int&();
} b;
A& ra = b;
const A& rca = b;
int& ir = B();
}
namespace std_example_2 {
double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}}
int i = 2;
double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a value of unrelated type 'int'}}
struct A { };
struct B : A { } b;
extern B f();
const A& rca = f();
A&& rra = f();
struct X {
operator B(); // expected-note{{candidate function}}
operator int&(); // expected-note{{candidate function}}
} x;
const A& r = x;
int&& rri = static_cast<int&&>(i);
B&& rrb = x;
int&& rri2 = X(); // expected-error{{no viable conversion from 'std_example_2::X' to 'int'}}
const double& rcd2 = 2;
double&& rrd = 2;
const volatile int cvi = 1;
const int& r2 = cvi; // expected-error{{binding of reference to type 'const int' to a value of type 'const volatile int' drops qualifiers}}
double d;
double&& rrd2 = d; // expected-error{{rvalue reference to type 'double' cannot bind to lvalue of type 'double'}}
double&& rrd3 = i;
}
namespace argument_passing {
void base_rvalue_ref(Base&&);
void int_rvalue_ref(int&&); // expected-note{{candidate function not viable: no known conversion from 'ConvertsTo<int &>' to 'int &&' for 1st argument}} \
// expected-note{{candidate function not viable: no known conversion from 'ConvertsTo<float &>' to 'int &&' for 1st argument}}
void array_rvalue_ref(int (&&)[5]);
void function_rvalue_ref(int (&&)(int));
void test() {
base_rvalue_ref(xvalue<Base>());
base_rvalue_ref(xvalue<Derived>());
int_rvalue_ref(xvalue<int>());
base_rvalue_ref(prvalue<Base>());
base_rvalue_ref(prvalue<Derived>());
array_rvalue_ref(HasArray().array);
function_rvalue_ref(f);
base_rvalue_ref(ConvertsTo<Base&&>());
base_rvalue_ref(ConvertsTo<Derived&&>());
int_rvalue_ref(ConvertsTo<int&&>());
base_rvalue_ref(ConvertsTo<Base>());
base_rvalue_ref(ConvertsTo<Derived>());
function_rvalue_ref(ConvertsTo<int(&)(int)>());
int_rvalue_ref(ConvertsTo<int&>()); // expected-error{{no matching function for call to 'int_rvalue_ref'}}
int_rvalue_ref(ConvertsTo<float&>()); // expected-error{{no matching function for call to 'int_rvalue_ref'}}
}
}
namespace pr10644 {
struct string {
string(const char* __s);
};
class map {
int& operator[](const string& __k);
public:
int& operator[](const string&& __k);
};
void foo() {
static map key_map;
key_map["line"];
}
}
namespace PR11003 {
class Value {
};
struct MoveRef {
operator Value &() const ;
};
MoveRef Move(int);
void growTo() {
Value x = Move(0);
Value y(Move(0));
}
}
namespace rdar13278115 {
struct X { };
struct Y : X { };
X &&f0(X &x) { return x; } // expected-error{{rvalue reference to type 'rdar13278115::X' cannot bind to lvalue of type 'rdar13278115::X'}}
X &&f1(Y &y) { return y; } // expected-error{{rvalue reference to type 'rdar13278115::X' cannot bind to lvalue of type 'rdar13278115::Y'}}
const X &&f2(Y &y) { return y; } // expected-error{{rvalue reference to type 'const rdar13278115::X' cannot bind to lvalue of type 'rdar13278115::Y'}}
}
namespace bitfields {
struct IntBitfield {
int i : 17; // expected-note 3 {{bit-field is declared here}}
};
// A simplified version of std::move.
template <typename T>
T &&move(T &obj) {
return static_cast<T &&>(obj);
}
void test() {
int & ir1 = (lvalue<IntBitfield>().i); // expected-error{{non-const reference cannot bind to bit-field 'i'}}
int & ir2 = (xvalue<IntBitfield>().i); // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
int && ir3 = (xvalue<IntBitfield>().i); // no-warning
int && ir4 = move(lvalue<IntBitfield>()).i; // no-warning
volatile int & vir1 = (lvalue<IntBitfield>().i); // expected-error{{non-const reference cannot bind to bit-field 'i'}}
volatile int & vir2 = (xvalue<IntBitfield>().i); // expected-error{{volatile lvalue reference to type 'volatile int' cannot bind to a temporary of type 'int'}}
volatile int && vir3 = (xvalue<IntBitfield>().i); // no-warning
volatile int && vir4 = move(lvalue<IntBitfield>()).i; // no-warning
const int & cir1 = (lvalue<IntBitfield>().i); // no-warning
const int & cir2 = (xvalue<IntBitfield>().i); // no-warning
const int && cir3 = (xvalue<IntBitfield>().i); // no-warning
const int && cir4 = move(lvalue<IntBitfield>()).i; // no-warning
const volatile int & cvir1 = (lvalue<IntBitfield>().i); // expected-error{{non-const reference cannot bind to bit-field 'i'}}
const volatile int & cvir2 = (xvalue<IntBitfield>().i); // expected-error{{volatile lvalue reference to type 'const volatile int' cannot bind to a temporary of type 'int'}}
const volatile int && cvir3 = (xvalue<IntBitfield>().i); // no-warning
const volatile int && cvir4 = move(lvalue<IntBitfield>()).i; // no-warning
}
}