[ObjC++] Conversions from specialized to non-specialized Objective-C generic
object types should be preferred over conversions to other object pointers

This change ensures that Clang will select the correct overload for the
following code sample:

  void overload(Base *b);
  void overload(Derived *d);
  void test(Base<Base *> b) {
    overload(b); // Select overload(Base *), not overload(Derived *)
  }

rdar://20124827

Differential Revision: https://reviews.llvm.org/D31597

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@299648 91177308-0d34-0410-b5e6-96231b3b80d8
(cherry picked from commit 0974a6fc550074bf804a8d1c359a1ff970e4a75c)
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index a1fd632..f666026 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -4048,7 +4048,7 @@
         = S.Context.canAssignObjCInterfaces(ToPtr1, ToPtr2);
       bool ToAssignRight
         = S.Context.canAssignObjCInterfaces(ToPtr2, ToPtr1);
-      
+
       // A conversion to an a non-id object pointer type or qualified 'id' 
       // type is better than a conversion to 'id'.
       if (ToPtr1->isObjCIdType() &&
@@ -4082,11 +4082,25 @@
         return ImplicitConversionSequence::Better;
 
       //   -- "conversion of C* to B* is better than conversion of C* to A*,"
-      if (S.Context.hasSameType(FromType1, FromType2) && 
+      if (S.Context.hasSameType(FromType1, FromType2) &&
           !FromPtr1->isObjCIdType() && !FromPtr1->isObjCClassType() &&
-          (ToAssignLeft != ToAssignRight))
+          (ToAssignLeft != ToAssignRight)) {
+        if (FromPtr1->isSpecialized()) {
+          // "conversion of B<A> * to B * is better than conversion of B * to
+          // C *.
+          bool IsFirstSame =
+              FromPtr1->getInterfaceDecl() == ToPtr1->getInterfaceDecl();
+          bool IsSecondSame =
+              FromPtr1->getInterfaceDecl() == ToPtr2->getInterfaceDecl();
+          if (IsFirstSame) {
+            if (!IsSecondSame)
+              return ImplicitConversionSequence::Better;
+          } else if (IsSecondSame)
+            return ImplicitConversionSequence::Worse;
+        }
         return ToAssignLeft? ImplicitConversionSequence::Worse
                            : ImplicitConversionSequence::Better;
+      }
 
       //   -- "conversion of B* to A* is better than conversion of C* to A*,"
       if (S.Context.hasSameUnqualifiedType(ToType1, ToType2) &&
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index bb94d9e..018afc9 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -174,3 +174,30 @@
   void f(Class) { }
   void f(id) { }
 }
+
+@interface NSDictionary<__covariant KeyType, __covariant ObjectType> : A
+@end
+
+@interface NSMutableDictionary<KeyType, ObjectType> : NSDictionary<KeyType, ObjectType>
+@end
+
+namespace rdar20124827 {
+
+int overload(NSDictionary *) { return 1; }
+
+__attribute__((deprecated))  // expected-note {{'overload' has been explicitly marked deprecated here}}
+int overload(NSMutableDictionary *) { return 0; }
+
+__attribute__((deprecated))
+void overload2(NSDictionary *); // expected-note {{candidate function}}
+void overload2(NSDictionary<A *, A *> *); // expected-note {{candidate function}}
+
+void test(NSDictionary *d1, NSDictionary<A *, A *> *d2, NSMutableDictionary<A *, A *> *m1) {
+  overload(d1);
+  overload(d2); // no warning
+  overload(m1); // expected-warning {{'overload' is deprecated}}
+  overload2(d2); // no warning
+  overload2(m1); // expected-error {{call to 'overload2' is ambiguous}}
+}
+
+}