]> granicus.if.org Git - clang/commitdiff
Tweak our handling of the notion of a standard conversion sequence
authorDouglas Gregor <dgregor@apple.com>
Wed, 9 Jun 2010 03:53:18 +0000 (03:53 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 9 Jun 2010 03:53:18 +0000 (03:53 +0000)
being a subsequence of another standard conversion sequence. Instead
of requiring exact type equality for the second conversion step,
require type *similarity*, which is type equality with cv-qualifiers
removed at all levels. This appears to match the behavior of EDG and
VC++ (albeit not GCC), and feels more intuitive. Big thanks to John
for the line of reasoning that supports this change: since
cv-qualifiers are orthogonal to the second conversion step, we should
ignore them in the type comparison.

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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/Sema.h
lib/Sema/SemaCXXCast.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaType.cpp
test/SemaCXX/overload-call.cpp

index b2da3d0b73c977c112a9deb0a461ae9383d4fdf8..9746b0dfd3fa80553b3d4e07542c1a2203a664d6 100644 (file)
@@ -1015,6 +1015,8 @@ public:
     return UnqualT1 == UnqualT2;
   }
 
+  bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
+  
   /// \brief Retrieves the "canonical" declaration of
 
   /// \brief Retrieves the "canonical" nested name specifier for a
index 75af89ee96a9642596b96ebb04955da238be9d90..2e7244957564426f98317fc0066caf21bbbfe8d5 100644 (file)
@@ -2339,6 +2339,48 @@ QualType ASTContext::getUnqualifiedArrayType(QualType T,
                                     SourceRange());
 }
 
+/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer 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 ignored. 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 ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) {
+  const PointerType *T1PtrType = T1->getAs<PointerType>(),
+                    *T2PtrType = T2->getAs<PointerType>();
+  if (T1PtrType && T2PtrType) {
+    T1 = T1PtrType->getPointeeType();
+    T2 = T2PtrType->getPointeeType();
+    return true;
+  }
+  
+  const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
+                          *T2MPType = T2->getAs<MemberPointerType>();
+  if (T1MPType && T2MPType && 
+      hasSameUnqualifiedType(QualType(T1MPType->getClass(), 0), 
+                             QualType(T2MPType->getClass(), 0))) {
+    T1 = T1MPType->getPointeeType();
+    T2 = T2MPType->getPointeeType();
+    return true;
+  }
+  
+  if (getLangOptions().ObjC1) {
+    const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
+                                *T2OPType = T2->getAs<ObjCObjectPointerType>();
+    if (T1OPType && T2OPType) {
+      T1 = T1OPType->getPointeeType();
+      T2 = T2OPType->getPointeeType();
+      return true;
+    }
+  }
+  
+  // FIXME: Block pointers, too?
+  
+  return false;
+}
+
 DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
   if (TemplateDecl *TD = Name.getAsTemplateDecl())
     return TD->getDeclName();
index 25f4e9d6c1854c99d8d1bc931a2423e45f98d1c1..48b8d05d918f05ced8237d891726c3da094de691 100644 (file)
@@ -769,8 +769,6 @@ public:
       const FunctionProtoType *Target, SourceLocation TargetLoc,
       const FunctionProtoType *Source, SourceLocation SourceLoc);
 
-  bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
-
   virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
 
   bool RequireCompleteType(SourceLocation Loc, QualType T,
index 5485bb3e17ac9a48ef869d0c544d73cfc52b5a14..16f0af14d27f3bd4a4652aa892e60f852f06a927 100644 (file)
@@ -1019,7 +1019,7 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
   // in multi-level pointers may change, but the level count must be the same,
   // as must be the final pointee type.
   while (SrcType != DestType &&
-         Self.UnwrapSimilarPointerTypes(SrcType, DestType)) {
+         Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) {
     Qualifiers Quals;
     SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals);
     DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals);
index d746ec3f6dc5c79e07a8f938d9fef98a1c2edd37..721c68f6c1dbd8be34d2712e3cbf0f796f712b9e 100644 (file)
@@ -1785,7 +1785,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
   //   in multi-level pointers, subject to the following rules: [...]
   bool PreviousToQualsIncludeConst = true;
   bool UnwrappedAnyPointer = false;
-  while (UnwrapSimilarPointerTypes(FromType, ToType)) {
+  while (Context.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
@@ -2073,6 +2073,16 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
   return ImplicitConversionSequence::Indistinguishable;
 }
 
+static bool hasSimilarType(ASTContext &Context, QualType T1, QualType T2) {
+  while (Context.UnwrapSimilarPointerTypes(T1, T2)) {
+    Qualifiers Quals;
+    T1 = Context.getUnqualifiedArrayType(T1, Quals);
+    T2 = Context.getUnqualifiedArrayType(T2, Quals);    
+  }
+  
+  return Context.hasSameUnqualifiedType(T1, T2);
+}
+  
 // 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
@@ -2098,7 +2108,7 @@ compareStandardConversionSubsets(ASTContext &Context,
       Result = ImplicitConversionSequence::Worse;
     else
       return ImplicitConversionSequence::Indistinguishable;
-  } else if (!Context.hasSameType(SCS1.getToType(1), SCS2.getToType(1)))
+  } else if (!hasSimilarType(Context, SCS1.getToType(1), SCS2.getToType(1)))
     return ImplicitConversionSequence::Indistinguishable;
 
   if (SCS1.Third == SCS2.Third) {
@@ -2305,7 +2315,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
 
   ImplicitConversionSequence::CompareKind Result
     = ImplicitConversionSequence::Indistinguishable;
-  while (UnwrapSimilarPointerTypes(T1, T2)) {
+  while (Context.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
index 8242f61897e0919b804999b3dc1a0699fffc4514..8327fd2686470ef084e0832844e3fcceb20c4866 100644 (file)
@@ -1611,45 +1611,6 @@ void LocInfoType::getAsStringInternal(std::string &Str,
          " GetTypeFromParser");
 }
 
-/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer 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 ignored. 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->getAs<PointerType>(),
-                    *T2PtrType = T2->getAs<PointerType>();
-  if (T1PtrType && T2PtrType) {
-    T1 = T1PtrType->getPointeeType();
-    T2 = T2PtrType->getPointeeType();
-    return true;
-  }
-
-  const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
-                          *T2MPType = T2->getAs<MemberPointerType>();
-  if (T1MPType && T2MPType &&
-      Context.getCanonicalType(T1MPType->getClass()) ==
-      Context.getCanonicalType(T2MPType->getClass())) {
-    T1 = T1MPType->getPointeeType();
-    T2 = T2MPType->getPointeeType();
-    return true;
-  }
-
-  if (getLangOptions().ObjC1) {
-    const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(),
-                                *T2OPType = T2->getAs<ObjCObjectPointerType>();
-    if (T1OPType && T2OPType) {
-      T1 = T1OPType->getPointeeType();
-      T2 = T2OPType->getPointeeType();
-      return true;
-    }
-  }
-  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.
index 29133c7c7ff100c6d13ae6dc3b9d69bc8dd997d4..9df5bc9f0c74bd4286a63cddedc814c1431259ab 100644 (file)
@@ -460,3 +460,20 @@ namespace PR7224 {
     float &fr = foo(d2);
   }
 }
+
+namespace NontrivialSubsequence {
+  struct X0;
+
+  class A {
+    operator X0 *();
+  public:
+    operator const X0 *();
+  };
+  A a;
+  void foo( void const * );
+
+  void g() {
+    foo(a);
+  }
+}