Remove a bunch of FIXME's related to ObjC type checking.
- Move Sema::ObjCQualifiedIdTypesAreCompatible(), Sema::QualifiedIdConformsQualifiedId(), and a couple helper functions to ASTContext.
- Change ASTContext::canAssignObjCInterfaces() to use ASTContext:: ObjCQualifiedIdTypesAreCompatible().
- Tweak several test cases to accommodate the new/improved type checking.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76830 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3bb763a..9f3eff9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1201,7 +1201,6 @@
bool &IncompleteImpl);
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
ObjCMethodDecl *IntfMethod);
- bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
NamespaceDecl *GetStdNamespace();
@@ -3197,9 +3196,6 @@
unsigned NewWidth, bool NewSign,
SourceLocation Loc, unsigned DiagID);
- bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
- bool ForCompare);
-
/// Checks that the Objective-C declaration is declared in the global scope.
/// Emits an error and marks the declaration as invalid if it's not declared
/// in the global scope.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 19cbf09..8bd2f53 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -369,7 +369,7 @@
if (!Context.typesAreCompatible(LHSType, RHSType)) {
// FIXME: Incorporate this test with typesAreCompatible.
if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
- if (ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
+ if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
return;
Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
<< Property->getType() << SuperProperty->getType() << inheritedName;
@@ -804,8 +804,8 @@
ObjCMethodDecl *IntfMethodDecl) {
if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(),
ImpMethodDecl->getResultType()) &&
- !QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
- ImpMethodDecl->getResultType())) {
+ !Context.QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
+ ImpMethodDecl->getResultType())) {
Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types)
<< ImpMethodDecl->getDeclName() << IntfMethodDecl->getResultType()
<< ImpMethodDecl->getResultType();
@@ -816,7 +816,8 @@
IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
IM != EM; ++IM, ++IF) {
if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) ||
- QualifiedIdConformsQualifiedId((*IF)->getType(), (*IM)->getType()))
+ Context.QualifiedIdConformsQualifiedId((*IF)->getType(),
+ (*IM)->getType()))
continue;
Diag((*IM)->getLocation(), diag::warn_conflicting_param_types)
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5d4fbd8..bfde991 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3171,7 +3171,7 @@
compositeType = RHSTy;
} else if ((LHSTy->isObjCQualifiedIdType() ||
RHSTy->isObjCQualifiedIdType()) &&
- ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
// Need to handle "id<xx>" explicitly.
// GCC allows qualified id and any Objective-C type to devolve to
// id. Currently localizing to here until clear this should be
@@ -3436,17 +3436,6 @@
return Compatible;
return Incompatible;
}
- // FIXME: Look into removing. With ObjCObjectPointerType, I don't see a need.
- if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
- if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
- return Compatible;
- // Relax integer conversions like we do for pointers below.
- if (rhsType->isIntegerType())
- return IntToPointer;
- if (lhsType->isIntegerType())
- return PointerToInt;
- return IncompatibleObjCQualifiedId;
- }
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
// to the same ExtVector type.
if (lhsType->isExtVectorType()) {
@@ -3528,6 +3517,8 @@
return Compatible;
if (Context.typesAreCompatible(lhsType, rhsType))
return Compatible;
+ if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+ return IncompatibleObjCQualifiedId;
return IncompatiblePointer;
}
if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 2d14410..47ce949 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -651,196 +651,3 @@
rbrac, ArgExprs, NumArgs);
}
-//===----------------------------------------------------------------------===//
-// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
-//===----------------------------------------------------------------------===//
-
-/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
-/// inheritance hierarchy of 'rProto'.
-static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
- ObjCProtocolDecl *rProto) {
- if (lProto == rProto)
- return true;
- for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
- E = rProto->protocol_end(); PI != E; ++PI)
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
- return true;
- return false;
-}
-
-/// ClassImplementsProtocol - Checks that 'lProto' protocol
-/// has been implemented in IDecl class, its super class or categories (if
-/// lookupCategory is true).
-static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
- ObjCInterfaceDecl *IDecl,
- bool lookupCategory,
- bool RHSIsQualifiedID = false) {
-
- // 1st, look up the class.
- const ObjCList<ObjCProtocolDecl> &Protocols =
- IDecl->getReferencedProtocols();
-
- for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(),
- E = Protocols.end(); PI != E; ++PI) {
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
- return true;
- // This is dubious and is added to be compatible with gcc. In gcc, it is
- // also allowed assigning a protocol-qualified 'id' type to a LHS object
- // when protocol in qualified LHS is in list of protocols in the rhs 'id'
- // object. This IMO, should be a bug.
- // FIXME: Treat this as an extension, and flag this as an error when GCC
- // extensions are not enabled.
- if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto))
- return true;
- }
-
- // 2nd, look up the category.
- if (lookupCategory)
- for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory()) {
- for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
- E = CDecl->protocol_end(); PI != E; ++PI)
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
- return true;
- }
-
- // 3rd, look up the super class(s)
- if (IDecl->getSuperClass())
- return
- ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory,
- RHSIsQualifiedID);
-
- return false;
-}
-
-/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
-/// return true if lhs's protocols conform to rhs's protocol; false
-/// otherwise.
-bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
- if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
- return false;
-}
-
-/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
-/// ObjCQualifiedIDType.
-/// FIXME: Move to ASTContext::typesAreCompatible() and friends.
-bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
- bool compare) {
- // Allow id<P..> and an 'id' or void* type in all cases.
- if (lhs->isVoidPointerType() ||
- lhs->isObjCIdType() || lhs->isObjCClassType())
- return true;
- else if (rhs->isVoidPointerType() ||
- rhs->isObjCIdType() || rhs->isObjCClassType())
- return true;
-
- if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
- const ObjCObjectPointerType *rhsOPT = rhs->getAsObjCObjectPointerType();
-
- if (!rhsOPT) return false;
-
- if (rhsOPT->qual_empty()) {
- // If the RHS is a unqualified interface pointer "NSString*",
- // make sure we check the class hierarchy.
- if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- if (!ClassImplementsProtocol(*I, rhsID, true))
- return false;
- }
- }
- // If there are no qualifiers and no interface, we have an 'id'.
- return true;
- }
- // Both the right and left sides have qualifiers.
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *lhsProto = *I;
- bool match = false;
-
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
- E = rhsOPT->qual_end(); J != E; ++J) {
- ObjCProtocolDecl *rhsProto = *J;
- if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
- (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
- match = true;
- break;
- }
- }
- // If the RHS is a qualified interface pointer "NSString<P>*",
- // make sure we check the class hierarchy.
- if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- if (ClassImplementsProtocol(*I, rhsID, true)) {
- match = true;
- break;
- }
- }
- }
- if (!match)
- return false;
- }
-
- return true;
- }
-
- const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
- assert(rhsQID && "One of the LHS/RHS should be id<x>");
-
- if (const ObjCObjectPointerType *lhsOPT =
- lhs->getAsObjCInterfacePointerType()) {
- if (lhsOPT->qual_empty()) {
- bool match = false;
- if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
- for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); I != E; ++I) {
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- if (ClassImplementsProtocol(*I, lhsID, true)) {
- match = true;
- break;
- }
- }
- if (!match)
- return false;
- }
- return true;
- }
- // Both the right and left sides have qualifiers.
- for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
- E = lhsOPT->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *lhsProto = *I;
- bool match = false;
-
- // when comparing an id<P> on lhs with a static type on rhs,
- // see if static class implements all of id's protocols, directly or
- // through its super class and categories.
- for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); J != E; ++J) {
- ObjCProtocolDecl *rhsProto = *J;
- if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
- (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
- match = true;
- break;
- }
- }
- if (!match)
- return false;
- }
- return true;
- }
- return false;
-}
-
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 503f226..dc5f3e8 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1020,7 +1020,8 @@
// Conversions with Objective-C's id<...>.
if ((FromObjCPtr->isObjCQualifiedIdType() ||
ToObjCPtr->isObjCQualifiedIdType()) &&
- ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
+ Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType,
+ /*compare=*/false)) {
ConvertedType = ToType;
return true;
}