[cfe-commits] r94660 - in /cfe/trunk: lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overload-call-copycon.cpp test/SemaCXX/overload-call.cpp

Douglas Gregor dgregor at apple.com
Tue Jan 26 19:51:04 PST 2010


Author: dgregor
Date: Tue Jan 26 21:51:04 2010
New Revision: 94660

URL: http://llvm.org/viewvc/llvm-project?rev=94660&view=rev
Log:
Fix a major oversight in the comparison of standard conversion
sequences, where we would occasionally determine (incorrectly) that
one standard conversion sequence was a proper subset of another when,
in fact, they contained completely incomparable conversions. 

This change records the types in each step within a standard
conversion sequence, so that we can check the specific comparison
types to determine when one sequence is a proper subset of the
other. Fixes this testcase (thanks, Anders!), which was distilled from
PR6095 (also thanks to Anders).

Modified:
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaOverload.h
    cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
    cfe/trunk/test/SemaCXX/overload-call.cpp

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=94660&r1=94659&r2=94660&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jan 26 21:51:04 2010
@@ -4455,7 +4455,9 @@
       ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
       ICS->Standard.Third = ICK_Identity;
       ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
-      ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+      ICS->Standard.setToType(0, T2);
+      ICS->Standard.setToType(1, T1);
+      ICS->Standard.setToType(2, T1);
       ICS->Standard.ReferenceBinding = true;
       ICS->Standard.DirectBinding = true;
       ICS->Standard.RRefBinding = false;
@@ -4645,7 +4647,9 @@
       ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
       ICS->Standard.Third = ICK_Identity;
       ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
-      ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+      ICS->Standard.setToType(0, T2);
+      ICS->Standard.setToType(1, T1);
+      ICS->Standard.setToType(2, T1);
       ICS->Standard.ReferenceBinding = true;
       ICS->Standard.DirectBinding = false;
       ICS->Standard.RRefBinding = isRValRef;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=94660&r1=94659&r2=94660&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jan 26 21:51:04 2010
@@ -1487,9 +1487,9 @@
 static QualType TargetType(const ImplicitConversionSequence &ICS) {
   switch (ICS.getKind()) {
   case ImplicitConversionSequence::StandardConversion:
-    return ICS.Standard.getToType();
+    return ICS.Standard.getToType(2);
   case ImplicitConversionSequence::UserDefinedConversion:
-    return ICS.UserDefined.After.getToType();
+    return ICS.UserDefined.After.getToType(2);
   case ImplicitConversionSequence::AmbiguousConversion:
     return ICS.Ambiguous.getToType();
   case ImplicitConversionSequence::EllipsisConversion:

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=94660&r1=94659&r2=94660&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jan 26 21:51:04 2010
@@ -148,7 +148,7 @@
   // array-to-pointer or function-to-pointer implicit conversions, so
   // check for their presence as well as checking whether FromType is
   // a pointer.
-  if (getToType()->isBooleanType() &&
+  if (getToType(1)->isBooleanType() &&
       (getFromType()->isPointerType() || getFromType()->isBlockPointerType() ||
        First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
     return true;
@@ -164,7 +164,7 @@
 StandardConversionSequence::
 isPointerConversionToVoidPointer(ASTContext& Context) const {
   QualType FromType = getFromType();
-  QualType ToType = getToType();
+  QualType ToType = getToType(1);
 
   // Note that FromType has not necessarily been transformed by the
   // array-to-pointer implicit conversion, so check for its presence
@@ -477,7 +477,7 @@
         ICS.setStandard();
         ICS.Standard.setAsIdentityConversion();
         ICS.Standard.setFromType(From->getType());
-        ICS.Standard.setToType(ToType);
+        ICS.Standard.setAllToTypes(ToType);
         ICS.Standard.CopyConstructor = Constructor;
         if (ToCanon != FromCanon)
           ICS.Standard.Second = ICK_Derived_To_Base;
@@ -595,7 +595,7 @@
       // conversion (4.4). (C++ 4.2p2)
       SCS.Second = ICK_Identity;
       SCS.Third = ICK_Qualification;
-      SCS.setToType(ToType);
+      SCS.setAllToTypes(FromType);
       return true;
     }
   } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
@@ -634,6 +634,7 @@
     // We don't require any conversions for the first step.
     SCS.First = ICK_Identity;
   }
+  SCS.setToType(0, FromType);
 
   // The second conversion can be an integral promotion, floating
   // point promotion, integral conversion, floating point conversion,
@@ -714,6 +715,7 @@
     // No second conversion required.
     SCS.Second = ICK_Identity;
   }
+  SCS.setToType(1, FromType);
 
   QualType CanonFrom;
   QualType CanonTo;
@@ -740,13 +742,13 @@
       CanonFrom = CanonTo;
     }
   }
+  SCS.setToType(2, FromType);
 
   // If we have not converted the argument type to the parameter type,
   // this is a bad conversion sequence.
   if (CanonFrom != CanonTo)
     return false;
 
-  SCS.setToType(FromType);
   return true;
 }
 
@@ -1605,7 +1607,7 @@
         User.After.setAsIdentityConversion();
         User.After.setFromType(
           ThisType->getAs<PointerType>()->getPointeeType());
-        User.After.setToType(ToType);
+        User.After.setAllToTypes(ToType);
         return OR_Success;
       } else if (CXXConversionDecl *Conversion
                    = dyn_cast<CXXConversionDecl>(Best->Function)) {
@@ -1722,6 +1724,43 @@
   return ImplicitConversionSequence::Indistinguishable;
 }
 
+// Per 13.3.3.2p3, compare the given standard conversion sequences to
+// determine if one is a proper subset of the other.
+static ImplicitConversionSequence::CompareKind
+compareStandardConversionSubsets(ASTContext &Context,
+                                 const StandardConversionSequence& SCS1,
+                                 const StandardConversionSequence& SCS2) {
+  ImplicitConversionSequence::CompareKind Result
+    = ImplicitConversionSequence::Indistinguishable;
+
+  if (SCS1.Second != SCS2.Second) {
+    if (SCS1.Second == ICK_Identity)
+      Result = ImplicitConversionSequence::Better;
+    else if (SCS2.Second == ICK_Identity)
+      Result = ImplicitConversionSequence::Worse;
+    else
+      return ImplicitConversionSequence::Indistinguishable;
+  } else if (!Context.hasSameType(SCS1.getToType(1), SCS2.getToType(1)))
+    return ImplicitConversionSequence::Indistinguishable;
+
+  if (SCS1.Third == SCS2.Third) {
+    return Context.hasSameType(SCS1.getToType(2), SCS2.getToType(2))? Result
+                             : ImplicitConversionSequence::Indistinguishable;
+  }
+
+  if (SCS1.Third == ICK_Identity)
+    return Result == ImplicitConversionSequence::Worse
+             ? ImplicitConversionSequence::Indistinguishable
+             : ImplicitConversionSequence::Better;
+
+  if (SCS2.Third == ICK_Identity)
+    return Result == ImplicitConversionSequence::Better
+             ? ImplicitConversionSequence::Indistinguishable
+             : ImplicitConversionSequence::Worse;
+       
+  return ImplicitConversionSequence::Indistinguishable;
+}
+
 /// CompareStandardConversionSequences - Compare two standard
 /// conversion sequences to determine whether one is better than the
 /// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -1737,21 +1776,9 @@
   //     excluding any Lvalue Transformation; the identity conversion
   //     sequence is considered to be a subsequence of any
   //     non-identity conversion sequence) or, if not that,
-  if (SCS1.Second == SCS2.Second && SCS1.Third == SCS2.Third)
-    // Neither is a proper subsequence of the other. Do nothing.
-    ;
-  else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) ||
-           (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) ||
-           (SCS1.Second == ICK_Identity &&
-            SCS1.Third == ICK_Identity))
-    // SCS1 is a proper subsequence of SCS2.
-    return ImplicitConversionSequence::Better;
-  else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) ||
-           (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) ||
-           (SCS2.Second == ICK_Identity &&
-            SCS2.Third == ICK_Identity))
-    // SCS2 is a proper subsequence of SCS1.
-    return ImplicitConversionSequence::Worse;
+  if (ImplicitConversionSequence::CompareKind CK
+        = compareStandardConversionSubsets(Context, SCS1, SCS2))
+    return CK;
 
   //  -- the rank of S1 is better than the rank of S2 (by the rules
   //     defined below), or, if not that,
@@ -1856,8 +1883,8 @@
     //      top-level cv-qualifiers, and the type to which the reference
     //      initialized by S2 refers is more cv-qualified than the type
     //      to which the reference initialized by S1 refers.
-    QualType T1 = SCS1.getToType();
-    QualType T2 = SCS2.getToType();
+    QualType T1 = SCS1.getToType(2);
+    QualType T2 = SCS2.getToType(2);
     T1 = Context.getCanonicalType(T1);
     T2 = Context.getCanonicalType(T2);
     Qualifiers T1Quals, T2Quals;
@@ -1898,8 +1925,8 @@
 
   // FIXME: the example in the standard doesn't use a qualification
   // conversion (!)
-  QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
-  QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+  QualType T1 = SCS1.getToType(2);
+  QualType T2 = SCS2.getToType(2);
   T1 = Context.getCanonicalType(T1);
   T2 = Context.getCanonicalType(T2);
   Qualifiers T1Quals, T2Quals;
@@ -1988,9 +2015,9 @@
 Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
                                       const StandardConversionSequence& SCS2) {
   QualType FromType1 = SCS1.getFromType();
-  QualType ToType1 = SCS1.getToType();
+  QualType ToType1 = SCS1.getToType(1);
   QualType FromType2 = SCS2.getFromType();
-  QualType ToType2 = SCS2.getToType();
+  QualType ToType2 = SCS2.getToType(1);
 
   // Adjust the types we're converting from via the array-to-pointer
   // conversion, if we need to.
@@ -2280,7 +2307,7 @@
   // Success. Mark this as a reference binding.
   ICS.setStandard();
   ICS.Standard.setFromType(FromType);
-  ICS.Standard.setToType(ImplicitParamType);
+  ICS.Standard.setAllToTypes(ImplicitParamType);
   ICS.Standard.ReferenceBinding = true;
   ICS.Standard.DirectBinding = true;
   ICS.Standard.RRefBinding = false;
@@ -2767,7 +2794,7 @@
   Candidate.IgnoreObjectArgument = false;
   Candidate.FinalConversion.setAsIdentityConversion();
   Candidate.FinalConversion.setFromType(Conversion->getConversionType());
-  Candidate.FinalConversion.setToType(ToType);
+  Candidate.FinalConversion.setAllToTypes(ToType);
 
   // Determine the implicit conversion sequence for the implicit
   // object parameter.

Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=94660&r1=94659&r2=94660&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Tue Jan 26 21:51:04 2010
@@ -139,9 +139,10 @@
     /// QualType.
     void *FromTypePtr;
 
-    /// ToType - The type that this conversion is converting to. This
-    /// is an opaque pointer that can be translated into a QualType.
-    void *ToTypePtr;
+    /// ToType - The types that this conversion is converting to in
+    /// each step. This is an opaque pointer that can be translated
+    /// into a QualType.
+    void *ToTypePtrs[3];
 
     /// CopyConstructor - The copy constructor that is used to perform
     /// this conversion, when the conversion is actually just the
@@ -151,12 +152,22 @@
     CXXConstructorDecl *CopyConstructor;
 
     void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
-    void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+    void setToType(unsigned Idx, QualType T) { 
+      assert(Idx < 3 && "To type index is out of range");
+      ToTypePtrs[Idx] = T.getAsOpaquePtr(); 
+    }
+    void setAllToTypes(QualType T) {
+      ToTypePtrs[0] = T.getAsOpaquePtr(); 
+      ToTypePtrs[1] = ToTypePtrs[0];
+      ToTypePtrs[2] = ToTypePtrs[0];
+    }
+
     QualType getFromType() const {
       return QualType::getFromOpaquePtr(FromTypePtr);
     }
-    QualType getToType() const {
-      return QualType::getFromOpaquePtr(ToTypePtr);
+    QualType getToType(unsigned Idx) const {
+      assert(Idx < 3 && "To type index is out of range");
+      return QualType::getFromOpaquePtr(ToTypePtrs[Idx]);
     }
 
     void setAsIdentityConversion();

Modified: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call-copycon.cpp?rev=94660&r1=94659&r2=94660&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call-copycon.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call-copycon.cpp Tue Jan 26 21:51:04 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s -Wnon-pod-varargs
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wnon-pod-varargs
 class X { };
 
 int& copycon(X x);
@@ -37,7 +37,6 @@
   float& f1 = copycon3(bc); // expected-warning {{cannot pass object of non-POD type}}
 }
 
-
 class C : public B { };
 
 float& copycon4(A a);

Modified: cfe/trunk/test/SemaCXX/overload-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=94660&r1=94659&r2=94660&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Tue Jan 26 21:51:04 2010
@@ -347,3 +347,15 @@
     foo(*P); // expected-error {{no matching function for call to 'foo'}}
   }
 }
+
+namespace DerivedToBaseVsVoid {
+  struct A { };
+  struct B : A { };
+  
+  float &f(void *);
+  int &f(const A*);
+  
+  void g(B *b) {
+    int &ir = f(b);
+  }
+}





More information about the cfe-commits mailing list