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>.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141137 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 836548a..6174bba 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -3324,6 +3324,16 @@
       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 @@
     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();
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
index a5a0d49..c1d3494 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
@@ -17,7 +17,7 @@
 
 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 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 @@
 
     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 @@
     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));
+  }
+}