[cfe-commits] r124591 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/SemaObjCXX/conversion-ranking.mm test/SemaObjCXX/overload.mm
Douglas Gregor
dgregor at apple.com
Mon Jan 31 10:51:41 PST 2011
Author: dgregor
Date: Mon Jan 31 12:51:41 2011
New Revision: 124591
URL: http://llvm.org/viewvc/llvm-project?rev=124591&view=rev
Log:
Implement reasonable conversion ranking for Objective-C pointer
conversions (<rdar://problem/8592139>) for overload resolution. The
conversion ranking mirrors C++'s conversion ranking fairly closely,
except that we use a same pseudo-subtyping relationship employed by
Objective-C pointer assignment rather than simple checking
derived-to-base conversions. This change covers:
- Conversions to pointers to a specific object type are better than
conversions to 'id', 'Class', qualified 'id', or qualified 'Class'
(note: GCC doesn't perform this ranking, but it matches C++'s rules
for ranking conversions to void*).
- Conversions to qualified 'id' or qualified 'Class' are better than
conversions to 'id' or 'Class', respectively.
- When two conversion sequences convert to the same type, rank the
conversions based on the relationship between the types we're
converting from.
- When two conversion sequences convert from the same non-id,
non-Class type, rank the conversions based on the relationship of
the types we're converting to. (note: GCC allows this ranking even
when converting from 'id', which is extremeley dangerous).
Added:
cfe/trunk/test/SemaObjCXX/conversion-ranking.mm
Modified:
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaObjCXX/overload.mm
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124591&r1=124590&r2=124591&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jan 31 12:51:41 2011
@@ -2651,9 +2651,6 @@
// If class B is derived directly or indirectly from class A and
// class C is derived directly or indirectly from B,
//
- // For Objective-C, we let A, B, and C also be Objective-C
- // interfaces.
-
// Compare based on pointer conversions.
if (SCS1.Second == ICK_Pointer_Conversion &&
SCS2.Second == ICK_Pointer_Conversion &&
@@ -2669,24 +2666,12 @@
QualType ToPointee2
= ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>();
- const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>();
- const ObjCObjectType* ToIface1 = ToPointee1->getAs<ObjCObjectType>();
- const ObjCObjectType* ToIface2 = ToPointee2->getAs<ObjCObjectType>();
-
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
if (S.IsDerivedFrom(ToPointee1, ToPointee2))
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(ToPointee2, ToPointee1))
return ImplicitConversionSequence::Worse;
-
- if (ToIface1 && ToIface2) {
- if (S.Context.canAssignObjCInterfaces(ToIface2, ToIface1))
- return ImplicitConversionSequence::Better;
- else if (S.Context.canAssignObjCInterfaces(ToIface1, ToIface2))
- return ImplicitConversionSequence::Worse;
- }
}
// -- conversion of B* to A* is better than conversion of C* to A*,
@@ -2695,16 +2680,79 @@
return ImplicitConversionSequence::Better;
else if (S.IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
+ }
+ } else if (SCS1.Second == ICK_Pointer_Conversion &&
+ SCS2.Second == ICK_Pointer_Conversion) {
+ const ObjCObjectPointerType *FromPtr1
+ = FromType1->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *FromPtr2
+ = FromType2->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *ToPtr1
+ = ToType1->getAs<ObjCObjectPointerType>();
+ const ObjCObjectPointerType *ToPtr2
+ = ToType2->getAs<ObjCObjectPointerType>();
+
+ if (FromPtr1 && FromPtr2 && ToPtr1 && ToPtr2) {
+ // Apply the same conversion ranking rules for Objective-C pointer types
+ // that we do for C++ pointers to class types. However, we employ the
+ // Objective-C pseudo-subtyping relationship used for assignment of
+ // Objective-C pointer types.
+ bool FromAssignLeft
+ = S.Context.canAssignObjCInterfaces(FromPtr1, FromPtr2);
+ bool FromAssignRight
+ = S.Context.canAssignObjCInterfaces(FromPtr2, FromPtr1);
+ bool ToAssignLeft
+ = 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() &&
+ (ToPtr2->isObjCQualifiedIdType() || ToPtr2->getInterfaceDecl()))
+ return ImplicitConversionSequence::Worse;
+ if (ToPtr2->isObjCIdType() &&
+ (ToPtr1->isObjCQualifiedIdType() || ToPtr1->getInterfaceDecl()))
+ return ImplicitConversionSequence::Better;
+
+ // A conversion to a non-id object pointer type is better than a
+ // conversion to a qualified 'id' type
+ if (ToPtr1->isObjCQualifiedIdType() && ToPtr2->getInterfaceDecl())
+ return ImplicitConversionSequence::Worse;
+ if (ToPtr2->isObjCQualifiedIdType() && ToPtr1->getInterfaceDecl())
+ return ImplicitConversionSequence::Better;
+
+ // A conversion to an a non-Class object pointer type or qualified 'Class'
+ // type is better than a conversion to 'Class'.
+ if (ToPtr1->isObjCClassType() &&
+ (ToPtr2->isObjCQualifiedClassType() || ToPtr2->getInterfaceDecl()))
+ return ImplicitConversionSequence::Worse;
+ if (ToPtr2->isObjCClassType() &&
+ (ToPtr1->isObjCQualifiedClassType() || ToPtr1->getInterfaceDecl()))
+ return ImplicitConversionSequence::Better;
+
+ // A conversion to a non-Class object pointer type is better than a
+ // conversion to a qualified 'Class' type.
+ if (ToPtr1->isObjCQualifiedClassType() && ToPtr2->getInterfaceDecl())
+ return ImplicitConversionSequence::Worse;
+ if (ToPtr2->isObjCQualifiedClassType() && ToPtr1->getInterfaceDecl())
+ return ImplicitConversionSequence::Better;
- if (FromIface1 && FromIface2) {
- if (S.Context.canAssignObjCInterfaces(FromIface1, FromIface2))
- return ImplicitConversionSequence::Better;
- else if (S.Context.canAssignObjCInterfaces(FromIface2, FromIface1))
- return ImplicitConversionSequence::Worse;
- }
+ // -- "conversion of C* to B* is better than conversion of C* to A*,"
+ if (S.Context.hasSameType(FromType1, FromType2) &&
+ !FromPtr1->isObjCIdType() && !FromPtr1->isObjCClassType() &&
+ (ToAssignLeft != ToAssignRight))
+ 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) &&
+ (FromAssignLeft != FromAssignRight))
+ return FromAssignLeft? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
}
}
-
+
// Ranking of member-pointer types.
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
Added: cfe/trunk/test/SemaObjCXX/conversion-ranking.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/conversion-ranking.mm?rev=124591&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/conversion-ranking.mm (added)
+++ cfe/trunk/test/SemaObjCXX/conversion-ranking.mm Mon Jan 31 12:51:41 2011
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+ at protocol P1
+ at end
+
+ at interface A <P1>
+ at end
+
+ at interface B : A
+ at end
+
+ at interface C : B
+ at end
+
+template<typename T>
+struct ConvertsTo {
+ operator T() const;
+};
+
+
+// conversion of C* to B* is better than conversion of C* to A*.
+int &f0(A*);
+float &f0(B*);
+
+void test_f0(C *c) {
+ float &fr1 = f0(c);
+}
+
+// conversion of B* to A* is better than conversion of C* to A*
+void f1(A*);
+
+struct ConvertsToBoth {
+private:
+ operator C*() const;
+
+public:
+ operator B*() const;
+};
+
+void test_f1(ConvertsTo<B*> toB, ConvertsTo<C*> toC, ConvertsToBoth toBoth) {
+ f1(toB);
+ f1(toC);
+ f1(toBoth);
+};
+
+// A conversion to an a non-id object pointer type is better than a
+// conversion to 'id'.
+int &f2(A*);
+float &f2(id);
+
+void test_f2(B *b) {
+ int &ir = f2(b);
+}
+
+// A conversion to an a non-Class object pointer type is better than a
+// conversion to 'Class'.
+int &f3(A*);
+float &f3(Class);
+
+void test_f3(B *b) {
+ int &ir = f3(b);
+}
+
+// When both conversions convert to 'id' or 'Class', pick the most
+// specific type to convert from.
+void f4(id);
+
+void test_f4(ConvertsTo<B*> toB, ConvertsTo<C*> toC, ConvertsToBoth toBoth) {
+ f4(toB);
+ f4(toC);
+ f4(toBoth);
+}
+
+void f5(id<P1>);
+
+void test_f5(ConvertsTo<B*> toB, ConvertsTo<C*> toC, ConvertsToBoth toBoth) {
+ f5(toB);
+ f5(toC);
+ f5(toBoth);
+}
+
+
+// A conversion to an a non-id object pointer type is better than a
+// conversion to qualified 'id'.
+int &f6(A*);
+float &f6(id<P1>);
+
+void test_f6(B *b) {
+ int &ir = f6(b);
+}
Modified: cfe/trunk/test/SemaObjCXX/overload.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/overload.mm?rev=124591&r1=124590&r2=124591&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/overload.mm (original)
+++ cfe/trunk/test/SemaObjCXX/overload.mm Mon Jan 31 12:51:41 2011
@@ -31,8 +31,8 @@
float& f(B*); // expected-note {{candidate}}
void g(A*);
-int& h(A*); // expected-note{{candidate}}
-float& h(id); // expected-note{{candidate}}
+int& h(A*);
+float& h(id);
void test0(A* a, B* b, id val) {
int& i1 = f(a);
@@ -47,8 +47,7 @@
int& i2 = h(a);
float& f3 = h(val);
- // FIXME: we match GCC here, but shouldn't this work?
- int& i3 = h(b); // expected-error{{call to 'h' is ambiguous}}
+ int& i3 = h(b);
}
void test1(A* a) {
@@ -114,13 +113,12 @@
}
// rdar://problem/8592139
-// FIXME: this should resolve to the unavailable candidate
namespace test6 {
- void foo(id); // expected-note {{candidate}}
+ void foo(id); // expected-note{{candidate function}}
void foo(A*) __attribute__((unavailable)); // expected-note {{explicitly made unavailable}}
void test(B *b) {
- foo(b); // expected-error {{call to 'foo' is ambiguous}}
+ foo(b); // expected-error {{call to unavailable function 'foo'}}
}
}
More information about the cfe-commits
mailing list