arphaman created this revision. Right now Clang will select incorrect overload when the Objective-C interface type is specialized, e.g.:
void overload(Base *b); void overload(Derived *d); void test(Base<Base *> b) { overload(b); // This will select (Derived *) overload } This patch ensures that the conversion from specialized to non-specialized type that points to the same interface is better than the other objective-c pointer conversions. Repository: rL LLVM https://reviews.llvm.org/D31597 Files: lib/Sema/SemaOverload.cpp test/SemaObjCXX/overload.mm Index: test/SemaObjCXX/overload.mm =================================================================== --- test/SemaObjCXX/overload.mm +++ 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}} +} + +} Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ 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) &&
Index: test/SemaObjCXX/overload.mm =================================================================== --- test/SemaObjCXX/overload.mm +++ 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}} +} + +} Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ 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) &&
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits