[cfe-commits] r57978 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h lib/Sema/SemaType.cpp test/SemaCXX/overload-call.cpp

Douglas Gregor doug.gregor at gmail.com
Wed Oct 22 07:17:16 PDT 2008


Author: dgregor
Date: Wed Oct 22 09:17:15 2008
New Revision: 57978

URL: http://llvm.org/viewvc/llvm-project?rev=57978&view=rev
Log:
Implement ranking of standard conversion sequences by their qualification
conversions (e.g., comparing int* -> const int* against 
int* -> const volatile int*); see C++ 13.3.3.2p3 bullet 3.

Add Sema::UnwrapSimilarPointerTypes to simplify the control flow of
IsQualificationConversion and CompareQualificationConversion (and fix
the handling of the int* -> volatile int* conversion in the former).
 

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

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct 22 09:17:15 2008
@@ -262,7 +262,8 @@
   
   QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
 
-  
+  bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
+
   virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
 private:
   //===--------------------------------------------------------------------===//
@@ -380,6 +381,10 @@
   CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
                                      const StandardConversionSequence& SCS2);
 
+  ImplicitConversionSequence::CompareKind 
+  CompareQualificationConversions(const StandardConversionSequence& SCS1,
+                                  const StandardConversionSequence& SCS2);
+
   /// OverloadingResult - Capture the result of performing overload
   /// resolution.
   enum OverloadingResult {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Oct 22 09:17:15 2008
@@ -659,46 +659,32 @@
   //   A conversion can add cv-qualifiers at levels other than the first
   //   in multi-level pointers, subject to the following rules: [...]
   bool PreviousToQualsIncludeConst = true;
-  bool UnwrappedPointer;
   bool UnwrappedAnyPointer = false;
-  do {
+  while (UnwrapSimilarPointerTypes(FromType, ToType)) {
     // Within each iteration of the loop, we check the qualifiers to
     // determine if this still looks like a qualification
     // conversion. Then, if all is well, we unwrap one more level of
     // pointers (FIXME: or pointers-to-members) and do it all again
     // until there are no more pointers or pointers-to-members left to
     // unwrap.
-    UnwrappedPointer = false;
-
-    //   -- the pointer types are similar.
-    const PointerType *FromPtrType = FromType->getAsPointerType(),
-                      *ToPtrType   = ToType->getAsPointerType();
-    if (FromPtrType && ToPtrType) {
-      // The pointer types appear similar. Look at their pointee types.
-      FromType = FromPtrType->getPointeeType();
-      ToType = ToPtrType->getPointeeType();
-      UnwrappedPointer = true;
-      UnwrappedAnyPointer = true;
-    } 
-
-    // FIXME: Cope with pointer-to-member types.
+    UnwrappedAnyPointer = true;
 
     //   -- for every j > 0, if const is in cv 1,j then const is in cv
     //      2,j, and similarly for volatile.
     if (!ToType.isAtLeastAsQualifiedAs(FromType))
       return false;
-
+    
     //   -- if the cv 1,j and cv 2,j are different, then const is in
     //      every cv for 0 < k < j.
     if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
-	&& !PreviousToQualsIncludeConst)
+        && !PreviousToQualsIncludeConst)
       return false;
-
+    
     // Keep track of whether all prior cv-qualifiers in the "to" type
     // include const.
     PreviousToQualsIncludeConst 
       = PreviousToQualsIncludeConst && ToType.isConstQualified();
-  } while (UnwrappedPointer);
+  }
 
   // We are left with FromType and ToType being the pointee types
   // after unwrapping the original FromType and ToType the same number
@@ -791,28 +777,122 @@
     return ImplicitConversionSequence::Better;
   else if (Rank2 < Rank1)
     return ImplicitConversionSequence::Worse;
-  else {
-    // (C++ 13.3.3.2p4): Two conversion sequences with the same rank
-    // are indistinguishable unless one of the following rules
-    // applies:
-    
-    //   A conversion that is not a conversion of a pointer, or
-    //   pointer to member, to bool is better than another conversion
-    //   that is such a conversion.
-    if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool())
-      return SCS2.isPointerConversionToBool()
-               ? ImplicitConversionSequence::Better
-               : ImplicitConversionSequence::Worse;
 
-    // FIXME: The other bullets in (C++ 13.3.3.2p4) require support
-    // for derived classes.
-  }
+  // (C++ 13.3.3.2p4): Two conversion sequences with the same rank
+  // are indistinguishable unless one of the following rules
+  // applies:
+  
+  //   A conversion that is not a conversion of a pointer, or
+  //   pointer to member, to bool is better than another conversion
+  //   that is such a conversion.
+  if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool())
+    return SCS2.isPointerConversionToBool()
+             ? ImplicitConversionSequence::Better
+             : ImplicitConversionSequence::Worse;
+
+  // FIXME: The other bullets in (C++ 13.3.3.2p4) require support
+  // for derived classes.
+
+  // Compare based on qualification conversions (C++ 13.3.3.2p3,
+  // bullet 3).
+  if (ImplicitConversionSequence::CompareKind CK 
+        = CompareQualificationConversions(SCS1, SCS2))
+    return CK;
 
-  // FIXME: Handle comparison by qualifications.
   // FIXME: Handle comparison of reference bindings.
+
   return ImplicitConversionSequence::Indistinguishable;
 }
 
+/// CompareQualificationConversions - Compares two standard conversion
+/// sequences to determine whether they can be ranked based on their
+/// qualification conversions (C++ 13.3.3.2p3 bullet 3). 
+ImplicitConversionSequence::CompareKind 
+Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
+                                      const StandardConversionSequence& SCS2)
+{
+  //  -- S1 and S2 differ only in their qualification conversion and
+  //     yield similar types T1 and T2 (C++ 4.4), respectively, and the
+  //     cv-qualification signature of type T1 is a proper subset of
+  //     the cv-qualification signature of type T2, and S1 is not the
+  //     deprecated string literal array-to-pointer conversion (4.2).
+  if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second ||
+      SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification)
+    return ImplicitConversionSequence::Indistinguishable;
+
+  // FIXME: the example in the standard doesn't use a qualification
+  // conversion (!)
+  QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
+  QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+  T1 = Context.getCanonicalType(T1);
+  T2 = Context.getCanonicalType(T2);
+
+  // If the types are the same, we won't learn anything by unwrapped
+  // them.
+  if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+    return ImplicitConversionSequence::Indistinguishable;
+
+  ImplicitConversionSequence::CompareKind Result 
+    = ImplicitConversionSequence::Indistinguishable;
+  while (UnwrapSimilarPointerTypes(T1, T2)) {
+    // Within each iteration of the loop, we check the qualifiers to
+    // determine if this still looks like a qualification
+    // conversion. Then, if all is well, we unwrap one more level of
+    // pointers (FIXME: or pointers-to-members) and do it all again
+    // until there are no more pointers or pointers-to-members left
+    // to unwrap. This essentially mimics what
+    // IsQualificationConversion does, but here we're checking for a
+    // strict subset of qualifiers.
+    if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+      // The qualifiers are the same, so this doesn't tell us anything
+      // about how the sequences rank.
+      ;
+    else if (T2.isMoreQualifiedThan(T1)) {
+      // T1 has fewer qualifiers, so it could be the better sequence.
+      if (Result == ImplicitConversionSequence::Worse)
+        // Neither has qualifiers that are a subset of the other's
+        // qualifiers.
+        return ImplicitConversionSequence::Indistinguishable;
+      
+      Result = ImplicitConversionSequence::Better;
+    } else if (T1.isMoreQualifiedThan(T2)) {
+      // T2 has fewer qualifiers, so it could be the better sequence.
+      if (Result == ImplicitConversionSequence::Better)
+        // Neither has qualifiers that are a subset of the other's
+        // qualifiers.
+        return ImplicitConversionSequence::Indistinguishable;
+      
+      Result = ImplicitConversionSequence::Worse;
+    } else {
+      // Qualifiers are disjoint.
+      return ImplicitConversionSequence::Indistinguishable;
+    }
+
+    // If the types after this point are equivalent, we're done.
+    if (T1.getUnqualifiedType() == T2.getUnqualifiedType())
+      break;
+  }
+
+  // Check that the winning standard conversion sequence isn't using
+  // the deprecated string literal array to pointer conversion.
+  switch (Result) {
+  case ImplicitConversionSequence::Better:
+    if (SCS1.Deprecated)
+      Result = ImplicitConversionSequence::Indistinguishable;
+    break;
+
+  case ImplicitConversionSequence::Indistinguishable:
+    break;
+
+  case ImplicitConversionSequence::Worse:
+    if (SCS2.Deprecated)
+      Result = ImplicitConversionSequence::Indistinguishable;
+    break;
+  }
+
+  return Result;
+}
+
 /// AddOverloadCandidate - Adds the given function to the set of
 /// candidate functions, using the given function call arguments.
 void 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Wed Oct 22 09:17:15 2008
@@ -170,9 +170,9 @@
     // sequences. Use Sema::CompareImplicitConversionSequences to
     // actually perform the comparison.
     enum CompareKind {
-      Better,
-      Indistinguishable,
-      Worse
+      Better = -1,
+      Indistinguishable = 0,
+      Worse = 1
     };
 
     void DebugPrint() const;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Oct 22 09:17:15 2008
@@ -535,6 +535,29 @@
   return T;
 }
 
+/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types (FIXME:
+/// or pointer-to-member types) that may be similar (C++ 4.4),
+/// replaces T1 and T2 with the type that they point to and return
+/// true. If T1 and T2 aren't pointer types or pointer-to-member
+/// types, or if they are not similar at this level, returns false and
+/// leaves T1 and T2 unchanged. Top-level qualifiers on T1 and T2 are
+/// ignord. This function will typically be called in a loop that
+/// successively "unwraps" pointer and pointer-to-member types to
+/// compare them at each level.
+bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2)
+{
+  const PointerType *T1PtrType = T1->getAsPointerType(),
+                    *T2PtrType = T2->getAsPointerType();
+  if (T1PtrType && T2PtrType) {
+    T1 = T1PtrType->getPointeeType();
+    T2 = T2PtrType->getPointeeType();
+    return true;
+  }
+
+  // FIXME: pointer-to-member types
+  return false;
+}
+
 Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
   // C99 6.7.6: Type names have no identifier.  This is already validated by
   // the parser.

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

==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Wed Oct 22 09:17:15 2008
@@ -156,11 +156,32 @@
 // Test overloading based on qualification ranking (C++ 13.3.2)p3.
 int* quals_rank1(int const * p);
 float* quals_rank1(int const volatile *p);
+char* quals_rank1(char*);
+double* quals_rank1(const char*);
 
 int* quals_rank2(int const * const * pp);
 float* quals_rank2(int * const * pp);
 
+void quals_rank3(int const * const * const volatile * p); // expected-note{{candidate function}}
+void quals_rank3(int const * const volatile * const * p); // expected-note{{candidate function}}
+
+void quals_rank3(int const *); // expected-note{{candidate function}}
+void quals_rank3(int volatile *); // expected-note{{candidate function}}
+
 void test_quals_ranking(int * p, int volatile *pq, int * * pp, int * * * ppp) {
-  //  int* q1 = quals_rank1(p);
+  int* q1 = quals_rank1(p);
   float* q2 = quals_rank1(pq); 
+  double* q3 = quals_rank1("string literal");
+  char a[17];
+  const char* ap = a;
+  char* q4 = quals_rank1(a);
+  double* q5 = quals_rank1(ap);
+
+  float* q6 = quals_rank2(pp);
+
+  quals_rank3(ppp); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+
+  quals_rank3(p); // expected-error {{call to 'quals_rank3' is ambiguous; candidates are:}}
+  quals_rank3(pq);
 }
+





More information about the cfe-commits mailing list