diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 836548aea793..6174bbac73c5 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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(); + 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()) { + 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(); diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp index a5a0d49afc43..c1d34941d4c4 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp @@ -17,7 +17,7 @@ int f(int); template 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' to 'int &&' for 1st argument}} \ + // expected-note{{candidate function not viable: no known conversion from 'ConvertsTo' 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_rvalue_ref(ConvertsTo()); // expected-error{{no viable conversion from 'ConvertsTo' to 'int'}} - int_rvalue_ref(ConvertsTo()); // expected-error{{no viable conversion from 'ConvertsTo' to 'int'}} + int_rvalue_ref(ConvertsTo()); // expected-error{{no matching function for call to 'int_rvalue_ref'}} + int_rvalue_ref(ConvertsTo()); // 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)); + } +}