[cfe-commits] r124121 - in /cfe/trunk: lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp test/SemaCXX/conditional-expr.cpp test/SemaCXX/decl-init-ref.cpp

Douglas Gregor dgregor at apple.com
Mon Jan 24 08:14:37 PST 2011


Author: dgregor
Date: Mon Jan 24 10:14:37 2011
New Revision: 124121

URL: http://llvm.org/viewvc/llvm-project?rev=124121&view=rev
Log:
Re-instate r123977/r123978, my updates of the reference-binding
implementation used by overload resolution to support rvalue
references. The original commits caused PR9026 and some
hard-to-reproduce self-host breakage.

The only (crucial!) difference between this commit and the previous
commits is that we now properly check the SuppressUserConversions flag
before attempting to perform a second user-defined conversion in
reference binding, breaking the infinite recursion chain of
user-defined conversions.

Rvalue references should be working a bit better now.

Modified:
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
    cfe/trunk/test/SemaCXX/conditional-expr.cpp
    cfe/trunk/test/SemaCXX/decl-init-ref.cpp

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124121&r1=124120&r2=124121&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jan 24 10:14:37 2011
@@ -2798,10 +2798,6 @@
   CXXRecordDecl *T2RecordDecl
     = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
 
-  QualType ToType
-    = AllowRvalues? DeclType->getAs<ReferenceType>()->getPointeeType()
-                  : DeclType;
-
   OverloadCandidateSet CandidateSet(DeclLoc);
   const UnresolvedSetImpl *Conversions
     = T2RecordDecl->getVisibleConversionFunctions();
@@ -2852,10 +2848,10 @@
     
     if (ConvTemplate)
       S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
-                                       Init, ToType, CandidateSet);
+                                       Init, DeclType, CandidateSet);
     else
       S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
-                               ToType, CandidateSet);
+                               DeclType, CandidateSet);
   }
 
   OverloadCandidateSet::iterator Best;
@@ -2944,9 +2940,7 @@
   //   of type "cv2 T2" as follows:
 
   //     -- If reference is an lvalue reference and the initializer expression
-  // The next bullet point (T1 is a function) is pretty much equivalent to this
-  // one, so it's handled here.
-  if (!isRValRef || T1->isFunctionType()) {
+  if (!isRValRef) {
     //     -- is an lvalue (but is not a bit-field), and "cv1 T1" is
     //        reference-compatible with "cv2 T2," or
     //
@@ -3001,8 +2995,7 @@
 
   //     -- 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 and the initializer expression shall be
-  //        an rvalue or have a function type.
+  //        shall be an rvalue reference.
   // 
   // We actually handle one oddity of C++ [over.ics.ref] at this
   // point, which is that, due to p2 (which short-circuits reference
@@ -3016,73 +3009,62 @@
   if (!isRValRef && !T1.isConstQualified())
     return ICS;
 
-  //       -- If T1 is a function type, then
-  //          -- if T2 is the same type as T1, the reference is bound to the
-  //             initializer expression lvalue;
-  //          -- if T2 is a class type and the initializer expression can be
-  //             implicitly converted to an lvalue of type T1 [...], the
-  //             reference is bound to the function lvalue that is the result
-  //             of the conversion;
-  // This is the same as for the lvalue case above, so it was handled there.
-  //          -- otherwise, the program is ill-formed.
-  // This is the one difference to the lvalue case.
-  if (T1->isFunctionType())
-    return ICS;
-
-  //       -- Otherwise, if T2 is a class type and
-  //          -- the initializer expression is an rvalue and "cv1 T1"
-  //             is reference-compatible with "cv2 T2," or
-  //
-  //          -- T1 is not reference-related to T2 and the initializer
-  //             expression can be implicitly converted to an rvalue
-  //             of type "cv3 T3" (this conversion is selected by
-  //             enumerating the applicable conversion functions
-  //             (13.3.1.6) and choosing the best one through overload
-  //             resolution (13.3)),
-  //
-  //          then the reference is bound to the initializer
-  //          expression rvalue in the first case and to the object
-  //          that is the result of the conversion in the second case
-  //          (or, in either case, to the appropriate base class
-  //          subobject of the object).
-  if (T2->isRecordType()) {
-    // First case: "cv1 T1" is reference-compatible with "cv2 T2". This is a
-    // direct binding in C++0x but not in C++03.
-    if (InitCategory.isRValue() && 
-        RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
-      ICS.setStandard();
-      ICS.Standard.First = ICK_Identity;
-      ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base 
-                          : ObjCConversion? ICK_Compatible_Conversion
-                          : ICK_Identity;
-      ICS.Standard.Third = ICK_Identity;
-      ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
-      ICS.Standard.setToType(0, T2);
-      ICS.Standard.setToType(1, T1);
-      ICS.Standard.setToType(2, T1);
-      ICS.Standard.ReferenceBinding = true;
-      ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x;
-      ICS.Standard.RRefBinding = isRValRef;
-      ICS.Standard.CopyConstructor = 0;
-      return ICS;
-    }
-    
-    // Second case: not reference-related.
-    if (RefRelationship == Sema::Ref_Incompatible &&
-        !S.RequireCompleteType(DeclLoc, T2, 0) && 
-        FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
-                                 Init, T2, /*AllowRvalues=*/true,
-                                 AllowExplicit)) {
-      // 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.
-      if (ICS.isUserDefined() && isRValRef && 
-          ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue)
-        ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
+  //       -- If the initializer expression
+  //
+  //            -- is an xvalue, class prvalue, array prvalue or function
+  //               lvalue and "cv1T1" is reference-compatible with "cv2 T2", or
+  if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification &&
+      (InitCategory.isXValue() ||
+      (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
+      (InitCategory.isLValue() && T2->isFunctionType()))) {
+    ICS.setStandard();
+    ICS.Standard.First = ICK_Identity;
+    ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base 
+                      : ObjCConversion? ICK_Compatible_Conversion
+                      : ICK_Identity;
+    ICS.Standard.Third = ICK_Identity;
+    ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+    ICS.Standard.setToType(0, T2);
+    ICS.Standard.setToType(1, T1);
+    ICS.Standard.setToType(2, T1);
+    ICS.Standard.ReferenceBinding = true;
+    // In C++0x, this is always a direct binding. In C++98/03, it's a direct
+    // binding unless we're binding to a class prvalue.
+    // Note: Although xvalues wouldn't normally show up in C++98/03 code, we
+    // allow the use of rvalue references in C++98/03 for the benefit of
+    // standard library implementors; therefore, we need the xvalue check here.
+    ICS.Standard.DirectBinding = 
+      S.getLangOptions().CPlusPlus0x || 
+      (InitCategory.isPRValue() && !T2->isRecordType());
+    ICS.Standard.RRefBinding = isRValRef;
+    ICS.Standard.CopyConstructor = 0;
+    return ICS; 
+  }
+  
+  //            -- 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",
+  //
+  //          then the reference is bound to the value of the initializer 
+  //          expression in the first case and to the result of the conversion
+  //          in the second case (or, in either case, to an appropriate base 
+  //          class subobject).
+  if (!SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible &&
+      T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) && 
+      FindConversionForRefInit(S, ICS, DeclType, DeclLoc,
+                               Init, T2, /*AllowRvalues=*/true,
+                               AllowExplicit)) {
+    // 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.
+    if (ICS.isUserDefined() && isRValRef && 
+        ICS.UserDefined.After.First == ICK_Lvalue_To_Rvalue)
+      ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
 
-      return ICS;
-    }
+    return ICS;
   }
   
   //       -- Otherwise, a temporary of type "cv1 T1" is created and

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124121&r1=124120&r2=124121&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Jan 24 10:14:37 2011
@@ -2470,6 +2470,7 @@
   TemplateParameterList::iterator Param = Params->begin(),
                                ParamEnd = Params->end();
   unsigned ArgIdx = 0;
+  LocalInstantiationScope InstScope(*this, true);
   while (Param != ParamEnd) {
     if (ArgIdx > NumArgs && PartialTemplateArgs)
       break;

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp?rev=124121&r1=124120&r2=124121&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp Mon Jan 24 10:14:37 2011
@@ -17,7 +17,7 @@
 
 template<typename T>
 struct ConvertsTo {
-  operator T(); // expected-note 2{{candidate function}}
+  operator T(); // expected-note 4{{candidate function}}
 };
 
 void test_rvalue_refs() {
@@ -130,3 +130,35 @@
   double&& rrd3 = i;
 }
 
+namespace argument_passing {
+  void base_rvalue_ref(Base&&);
+  void int_rvalue_ref(int&&); // expected-note 2{{passing argument to parameter here}}
+  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 viable conversion from 'ConvertsTo<int &>' to 'int'}}
+    int_rvalue_ref(ConvertsTo<float&>()); // expected-error{{no viable conversion from 'ConvertsTo<float &>' to 'int'}}
+  }
+
+}

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=124121&r1=124120&r2=124121&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Mon Jan 24 10:14:37 2011
@@ -7,7 +7,10 @@
 struct ToBool { explicit operator bool(); };
 
 struct B;
-struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
+struct A {
+  A(); 
+  A(const B&); // expected-note 2 {{candidate constructor}}
+}; 
 struct B { operator A() const; }; // expected-note 2 {{candidate function}}
 struct I { operator int(); };
 struct J { operator I(); };

Modified: cfe/trunk/test/SemaCXX/decl-init-ref.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-init-ref.cpp?rev=124121&r1=124120&r2=124121&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/decl-init-ref.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-init-ref.cpp Mon Jan 24 10:14:37 2011
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
 
-struct A {}; // expected-note {{candidate is the implicit copy constructor}}
+struct A {};
 
 struct BASE {
   operator A(); // expected-note {{candidate function}}





More information about the cfe-commits mailing list