[cfe-commits] r60130 - in /cfe/trunk: Driver/clang.cpp lib/Sema/SemaOverload.cpp test/SemaObjCXX/overload.mm
Douglas Gregor
doug.gregor at gmail.com
Wed Nov 26 15:31:11 PST 2008
Author: dgregor
Date: Wed Nov 26 17:31:11 2008
New Revision: 60130
URL: http://llvm.org/viewvc/llvm-project?rev=60130&view=rev
Log:
Implement implicit conversions for Objective-C specific types, e.g.,
converting a pointer to one Objective-C interface into a pointer to another
Objective-C interface, and conversions with 'id'. The semantics seems
to match GCC, although they seem somewhat ad hoc.
Fixed a few cases where we assumed the C++ definition of isObjectType,
but were getting the C definition, causing failures in trouble with
conversions to void pointers.
Added:
cfe/trunk/test/SemaObjCXX/overload.mm
Modified:
cfe/trunk/Driver/clang.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
Modified: cfe/trunk/Driver/clang.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/clang.cpp?rev=60130&r1=60129&r2=60130&view=diff
==============================================================================
--- cfe/trunk/Driver/clang.cpp (original)
+++ cfe/trunk/Driver/clang.cpp Wed Nov 26 17:31:11 2008
@@ -573,7 +573,7 @@
}
if (Options.CPlusPlus)
- Options.Blocks = 0;
+ Options.Blocks = 0;
}
static llvm::cl::opt<bool>
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=60130&r1=60129&r2=60130&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Nov 26 17:31:11 2008
@@ -709,6 +709,34 @@
return false;
}
+/// BuildSimilarlyQualifiedPointerType - In a pointer conversion from
+/// the pointer type FromPtr to a pointer to type ToPointee, with the
+/// same type qualifiers as FromPtr has on its pointee type. ToType,
+/// if non-empty, will be a pointer to ToType that may or may not have
+/// the right set of qualifiers on its pointee.
+static QualType
+BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
+ QualType ToPointee, QualType ToType,
+ ASTContext &Context) {
+ QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType());
+ QualType CanonToPointee = Context.getCanonicalType(ToPointee);
+ unsigned Quals = CanonFromPointee.getCVRQualifiers();
+
+ // Exact qualifier match -> return the pointer type we're converting to.
+ if (CanonToPointee.getCVRQualifiers() == Quals) {
+ // ToType is exactly what we need. Return it.
+ if (ToType.getTypePtr())
+ return ToType;
+
+ // Build a pointer to ToPointee. It has the right qualifiers
+ // already.
+ return Context.getPointerType(ToPointee);
+ }
+
+ // Just build a canonical type that has the right qualifiers.
+ return Context.getPointerType(CanonToPointee.getQualifiedType(Quals));
+}
+
/// IsPointerConversion - Determines whether the conversion of the
/// expression From, which has the (possibly adjusted) type FromType,
/// can be converted to the type ToType via a pointer conversion (C++
@@ -728,27 +756,20 @@
return true;
}
+ // Beyond this point, both types need to be pointers.
+ const PointerType *FromTypePtr = FromType->getAsPointerType();
+ if (!FromTypePtr)
+ return false;
+
+ QualType FromPointeeType = FromTypePtr->getPointeeType();
+ QualType ToPointeeType = ToTypePtr->getPointeeType();
+
// An rvalue of type "pointer to cv T," where T is an object type,
// can be converted to an rvalue of type "pointer to cv void" (C++
// 4.10p2).
- if (FromType->isPointerType() &&
- FromType->getAsPointerType()->getPointeeType()->isObjectType() &&
- ToTypePtr->getPointeeType()->isVoidType()) {
- // We need to produce a pointer to cv void, where cv is the same
- // set of cv-qualifiers as we had on the incoming pointee type.
- QualType toPointee = ToTypePtr->getPointeeType();
- unsigned Quals = Context.getCanonicalType(FromType)->getAsPointerType()
- ->getPointeeType().getCVRQualifiers();
-
- if (Context.getCanonicalType(ToTypePtr->getPointeeType()).getCVRQualifiers()
- == Quals) {
- // ToType is exactly the type we want. Use it.
- ConvertedType = ToType;
- } else {
- // Build a new type with the right qualifiers.
- ConvertedType
- = Context.getPointerType(Context.VoidTy.getQualifiedType(Quals));
- }
+ if (FromPointeeType->isIncompleteOrObjectType() && ToPointeeType->isVoidType()) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType,
+ ToType, Context);
return true;
}
@@ -765,32 +786,32 @@
//
// Note that we do not check for ambiguity or inaccessibility
// here. That is handled by CheckPointerConversion.
- if (const PointerType *FromPtrType = FromType->getAsPointerType())
- if (const PointerType *ToPtrType = ToType->getAsPointerType()) {
- if (FromPtrType->getPointeeType()->isRecordType() &&
- ToPtrType->getPointeeType()->isRecordType() &&
- IsDerivedFrom(FromPtrType->getPointeeType(),
- ToPtrType->getPointeeType())) {
- // The conversion is okay. Now, we need to produce the type
- // that results from this conversion, which will have the same
- // qualifiers as the incoming type.
- QualType CanonFromPointee
- = Context.getCanonicalType(FromPtrType->getPointeeType());
- QualType ToPointee = ToPtrType->getPointeeType();
- QualType CanonToPointee = Context.getCanonicalType(ToPointee);
- unsigned Quals = CanonFromPointee.getCVRQualifiers();
-
- if (CanonToPointee.getCVRQualifiers() == Quals) {
- // ToType is exactly the type we want. Use it.
- ConvertedType = ToType;
- } else {
- // Build a new type with the right qualifiers.
- ConvertedType
- = Context.getPointerType(CanonToPointee.getQualifiedType(Quals));
- }
- return true;
- }
- }
+ if (FromPointeeType->isRecordType() && ToPointeeType->isRecordType() &&
+ IsDerivedFrom(FromPointeeType, ToPointeeType)) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ // Objective C++: We're able to convert from a pointer to an
+ // interface to a pointer to a different interface.
+ const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
+ const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType();
+ if (FromIface && ToIface &&
+ Context.canAssignObjCInterfaces(ToIface, FromIface)) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
+ // Objective C++: We're able to convert between "id" and a pointer
+ // to any interface (in both directions).
+ if ((FromIface && Context.isObjCIdType(ToPointeeType))
+ || (ToIface && Context.isObjCIdType(FromPointeeType))) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType,
+ ToType, Context);
+ return true;
+ }
return false;
}
@@ -1125,6 +1146,17 @@
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
+
+ // Objective-C++: If one interface is more specific than the
+ // other, it is the better one.
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
+ if (FromIface1 && FromIface1) {
+ if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
+ return ImplicitConversionSequence::Better;
+ else if (Context.canAssignObjCInterfaces(FromIface1, FromIface2))
+ return ImplicitConversionSequence::Worse;
+ }
}
// Compare based on qualification conversions (C++ 13.3.3.2p3,
@@ -1247,7 +1279,9 @@
/// CompareDerivedToBaseConversions - Compares two standard conversion
/// sequences to determine whether they can be ranked based on their
-/// various kinds of derived-to-base conversions (C++ [over.ics.rank]p4b3).
+/// various kinds of derived-to-base conversions (C++
+/// [over.ics.rank]p4b3). As part of these checks, we also look at
+/// conversions between Objective-C interface types.
ImplicitConversionSequence::CompareKind
Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
@@ -1273,6 +1307,9 @@
//
// 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 &&
@@ -1285,12 +1322,25 @@
= FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
QualType ToPointee2
= ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType();
+
+ const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType();
+ const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType();
+ const ObjCInterfaceType* ToIface1 = ToPointee1->getAsObjCInterfaceType();
+ const ObjCInterfaceType* ToIface2 = ToPointee2->getAsObjCInterfaceType();
+
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
if (IsDerivedFrom(ToPointee1, ToPointee2))
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(ToPointee2, ToPointee1))
return ImplicitConversionSequence::Worse;
+
+ if (ToIface1 && ToIface2) {
+ if (Context.canAssignObjCInterfaces(ToIface2, ToIface1))
+ return ImplicitConversionSequence::Better;
+ else if (Context.canAssignObjCInterfaces(ToIface1, ToIface2))
+ return ImplicitConversionSequence::Worse;
+ }
}
// -- conversion of B* to A* is better than conversion of C* to A*,
@@ -1299,6 +1349,13 @@
return ImplicitConversionSequence::Better;
else if (IsDerivedFrom(FromPointee1, FromPointee2))
return ImplicitConversionSequence::Worse;
+
+ if (FromIface1 && FromIface2) {
+ if (Context.canAssignObjCInterfaces(FromIface1, FromIface2))
+ return ImplicitConversionSequence::Better;
+ else if (Context.canAssignObjCInterfaces(FromIface2, FromIface1))
+ return ImplicitConversionSequence::Worse;
+ }
}
}
@@ -2268,7 +2325,7 @@
for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin();
Ptr != CandidateTypes.pointer_end(); ++Ptr) {
// Skip pointer types that aren't pointers to object types.
- if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType())
+ if (!(*Ptr)->getAsPointerType()->getPointeeType()->isIncompleteOrObjectType())
continue;
QualType ParamTypes[2] = {
Added: cfe/trunk/test/SemaObjCXX/overload.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/overload.mm?rev=60130&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/overload.mm (added)
+++ cfe/trunk/test/SemaObjCXX/overload.mm Wed Nov 26 17:31:11 2008
@@ -0,0 +1,39 @@
+// RUN clang -fsyntax-only -verify %s
+ at interface A
+ at end
+
+ at interface B : A
+ at end
+
+int& f(A*);
+float& f(B*);
+void g(A*);
+
+int& h(A*);
+float& h(id);
+
+void test(A* a, B* b, id val) {
+ int& i1 = f(a);
+ float& f1 = f(b);
+ float& f2 = f(val);
+ g(a);
+ g(b);
+ g(val);
+ int& i2 = h(a);
+ float& f3 = h(val);
+ // int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
+}
+
+int& cv(A*);
+float& cv(const A*);
+int& cv2(void*);
+float& cv2(const void*);
+
+void cv_test(A* a, B* b, const A* ac, const B* bc) {
+ int &i1 = cv(a);
+ int &i2 = cv(b);
+ float &f1 = cv(ac);
+ float &f2 = cv(bc);
+ int& i3 = cv2(a);
+ float& f3 = cv2(ac);
+}
More information about the cfe-commits
mailing list