Don't allow an rvalue reference to bind to the result of a calling a

conversion function whose result type is an lvalue reference. The
initialization code already handled this properly, but overload
resolution was allowing the binding. Fixes PR11003 /
<rdar://problem/10233078>.

llvm-svn: 141137
This commit is contained in:
Douglas Gregor 2011-10-04 23:59:32 +00:00
parent 8569d2d8f2
commit b0e6c8a350
2 changed files with 42 additions and 4 deletions

View File

@ -3324,6 +3324,16 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
const ReferenceType *RefType
= Conv->getConversionType()->getAs<LValueReferenceType>();
if (RefType && !RefType->getPointeeType()->isFunctionType())
continue;
}
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
@ -3643,6 +3653,19 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = false;
} else if (ICS.isUserDefined()) {
// Don't allow rvalue references to bind to lvalues.
if (DeclType->isRValueReferenceType()) {
if (const ReferenceType *RefType
= ICS.UserDefined.ConversionFunction->getResultType()
->getAs<LValueReferenceType>()) {
if (!RefType->getPointeeType()->isFunctionType()) {
ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init,
DeclType);
return ICS;
}
}
}
ICS.UserDefined.After.ReferenceBinding = true;
ICS.UserDefined.After.IsLvalueReference = !isRValRef;
ICS.UserDefined.After.BindsToFunctionLvalue = T2->isFunctionType();

View File

@ -17,7 +17,7 @@ int f(int);
template<typename T>
struct ConvertsTo {
operator T(); // expected-note 4{{candidate function}}
operator T(); // expected-note 2{{candidate function}}
};
void test_rvalue_refs() {
@ -132,7 +132,9 @@ namespace std_example_2 {
namespace argument_passing {
void base_rvalue_ref(Base&&);
void int_rvalue_ref(int&&); // expected-note 2{{passing argument to parameter here}}
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));
@ -157,8 +159,8 @@ namespace argument_passing {
function_rvalue_ref(ConvertsTo<int(&)(int)>());
int_rvalue_ref(ConvertsTo<int&>()); // expected-error{{no viable conversion from 'ConvertsTo<int &>' to 'int'}}
int_rvalue_ref(ConvertsTo<float&>()); // expected-error{{no viable conversion from 'ConvertsTo<float &>' to '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'}}
}
}
@ -177,3 +179,16 @@ namespace pr10644 {
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));
}
}