]> granicus.if.org Git - clang/commitdiff
More work to bring reference binding up to the latest C++0x
authorDouglas Gregor <dgregor@apple.com>
Fri, 21 Jan 2011 00:52:42 +0000 (00:52 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 21 Jan 2011 00:52:42 +0000 (00:52 +0000)
specification. In particular, an rvalue reference can bind to an
initializer expression that is an lvalue if the referent type and the
initializer expression type are not reference-related. This is a newer
formulation to the previous "rvalue references can never bind to
lvalues" rule.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123952 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaInit.cpp
test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
test/SemaCXX/rval-references.cpp

index e25795de40bd2ed54411cae3afa830cf3bf89a78..59a393613162bec022402d3ec92d0eb934383ed5 100644 (file)
@@ -2571,23 +2571,19 @@ static void TryReferenceInitialization(Sema &S,
   //     - Otherwise, the reference shall be an lvalue reference to a 
   //       non-volatile const type (i.e., cv1 shall be const), or the reference
   //       shall be an rvalue reference.
-  if (!((isLValueRef && T1Quals.hasConst() && !T1Quals.hasVolatile()) ||
-        (isRValueRef && InitCategory.isRValue()))) {
+  if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile())) {
     if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)
       Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
     else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
       Sequence.SetOverloadFailure(
                         InitializationSequence::FK_ReferenceInitOverloadFailed,
                                   ConvOvlResult);
-    else if (isLValueRef)
+    else
       Sequence.SetFailed(InitCategory.isLValue()
         ? (RefRelationship == Sema::Ref_Related
              ? InitializationSequence::FK_ReferenceInitDropsQualifiers
              : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated)
         : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
-    else
-      Sequence.SetFailed(
-                    InitializationSequence::FK_RValueReferenceBindingToLValue);
 
     return;
   }
@@ -2696,6 +2692,15 @@ static void TryReferenceInitialization(Sema &S,
     return;
   }
 
+  //   [...] If T1 is reference-related to T2 and the reference is an rvalue 
+  //   reference, the initializer expression shall not be an lvalue.
+  if (RefRelationship >= Sema::Ref_Related && !isLValueRef && 
+      InitCategory.isLValue()) {
+    Sequence.SetFailed(
+                    InitializationSequence::FK_RValueReferenceBindingToLValue);
+    return;
+  }
+  
   Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
   return;
 }
index 4629cb64846b8f29c47bbf9ea9d523eb2ba8efa3..fe67d8a917c55a17bb7e06108a435a1cca8d3cdc 100644 (file)
@@ -17,7 +17,7 @@ int f(int);
 
 template<typename T>
 struct ConvertsTo {
-  operator T();
+  operator T(); // expected-note 2{{candidate function}}
 };
 
 void test_rvalue_refs() {
@@ -56,6 +56,13 @@ void test_rvalue_refs() {
 
   // 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 {
@@ -81,3 +88,20 @@ void test_direct_binding() {
   const NonCopyable &nc10 = ConvertsTo<NonCopyable&&>();
   const NonCopyable &nc11 = ConvertsTo<NonCopyableDerived&&>();
 }
+
+namespace std_example {
+  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 i;
+  int&& rri = static_cast<int&&>(i);
+  B&& rrb = x;
+  int&& rri2 = X(); // expected-error{{no viable conversion from 'std_example::X' to 'int'}}
+}
index 2068642c9d06004c73c2d29df9dcc433924dd27c..ee659ecbd2adb1d58cc8a5952e24d69f9a1d6320 100644 (file)
@@ -47,7 +47,7 @@ void f() {
   ilr_c2 vilr2 = i1;
 
   conv_to_not_int_rvalue cnir;
-  not_int &&ni4 = cnir; // expected-error {{rvalue reference cannot bind to lvalue}}
+  not_int &&ni4 = cnir;
   not_int &ni5 = cnir; // expected-error{{non-const lvalue reference to type 'not_int' cannot bind to a value of unrelated type 'conv_to_not_int_rvalue'}}
   not_int &&ni6 = conv_to_not_int_rvalue();