summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Naroff <snaroff@apple.com>2009-07-23 01:01:38 +0000
committerSteve Naroff <snaroff@apple.com>2009-07-23 01:01:38 +0000
commit4084c306635b70f37029dca938444e6013f08684 (patch)
treeb56a0713a869f492afd9af4920ffb7639e64fe80
parentd7b27e1c17d40c72a1ccf8868315bf0c5271aa54 (diff)
downloadclang-4084c306635b70f37029dca938444e6013f08684.tar.gz
clang-4084c306635b70f37029dca938444e6013f08684.tar.bz2
clang-4084c306635b70f37029dca938444e6013f08684.tar.xz
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
-rw-r--r--include/clang/AST/ASTContext.h3
-rw-r--r--lib/AST/ASTContext.cpp228
-rw-r--r--lib/Sema/Sema.h4
-rw-r--r--lib/Sema/SemaDeclObjC.cpp9
-rw-r--r--lib/Sema/SemaExpr.cpp15
-rw-r--r--lib/Sema/SemaExprObjC.cpp193
-rw-r--r--lib/Sema/SemaOverload.cpp3
-rw-r--r--test/SemaObjC/comptypes-1.m4
-rw-r--r--test/SemaObjC/comptypes-7.m4
-rw-r--r--test/SemaObjC/conditional-expr.m8
10 files changed, 219 insertions, 252 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 2637b68097..67fcff0db4 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -758,6 +758,9 @@ public:
assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
return T->getAsStructureType() == SelStructType;
}
+ bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
+ bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
+ bool ForCompare);
// Check the safety of assignment from LHS to RHS
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4490e9a3a9..727dc4ee3d 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3023,43 +3023,219 @@ static bool areCompatVectorTypes(const VectorType *LHS,
LHS->getNumElements() == RHS->getNumElements();
}
-/// canAssignObjCInterfaces - Return true if the two interface types are
-/// compatible for assignment from RHS to LHS. This handles validation of any
-/// protocol qualifiers on the LHS or RHS.
-///
-/// FIXME: Move the following to ObjCObjectPointerType/ObjCInterfaceType.
-bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
- const ObjCObjectPointerType *RHSOPT) {
- // If either type represents the built-in 'id' or 'Class' types, return true.
- if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType())
+//===----------------------------------------------------------------------===//
+// 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;
+}
- const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
- const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
- if (!LHS || !RHS) {
- // We have qualified builtin types.
+/// 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 ASTContext::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.
+bool ASTContext::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 = LHSOPT->qual_begin(),
- E = LHSOPT->qual_end(); I != E; ++I) {
- bool RHSImplementsProtocol = false;
+ 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) {
- if ((*J)->lookupProtocolNamed((*I)->getIdentifier())) {
- RHSImplementsProtocol = true;
+ 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 (!RHSImplementsProtocol)
+ // 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;
}
- // The RHS implements all protocols listed on the LHS.
+
return true;
}
- return canAssignObjCInterfaces(LHS, RHS);
+
+ 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;
+}
+
+/// canAssignObjCInterfaces - Return true if the two interface types are
+/// compatible for assignment from RHS to LHS. This handles validation of any
+/// protocol qualifiers on the LHS or RHS.
+///
+bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
+ const ObjCObjectPointerType *RHSOPT) {
+ // If either type represents the built-in 'id' or 'Class' types, return true.
+ if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType())
+ return true;
+
+ if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+ return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false);
+
+ const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
+ const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
+ if (LHS && RHS) // We have 2 user-defined types.
+ return canAssignObjCInterfaces(LHS, RHS);
+
+ return false;
}
bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
@@ -3087,7 +3263,7 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
// If the RHS doesn't implement the protocol on the left, the types
// are incompatible.
for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(),
- RHSPE = RHS->qual_end();
+ RHSPE = RHS->qual_end();
RHSPI != RHSPE; RHSPI++) {
if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) {
RHSImplementsProtocol = true;
@@ -3441,10 +3617,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return QualType();
}
case Type::ObjCObjectPointer: {
- // FIXME: Incorporate tests from Sema::ObjCQualifiedIdTypesAreCompatible().
- if (LHS->isObjCQualifiedIdType() && RHS->isObjCQualifiedIdType())
- return QualType();
-
if (canAssignObjCInterfaces(LHS->getAsObjCObjectPointerType(),
RHS->getAsObjCObjectPointerType()))
return LHS;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3bb763a13f..9f3eff9f1d 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1201,7 +1201,6 @@ public:
bool &IncompleteImpl);
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
ObjCMethodDecl *IntfMethod);
- bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
NamespaceDecl *GetStdNamespace();
@@ -3197,9 +3196,6 @@ public:
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 19cbf091b5..8bd2f530e4 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -369,7 +369,7 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
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 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
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 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
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 5d4fbd8080..bfde991555 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3171,7 +3171,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
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 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
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 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
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 2d144100e5..47ce949d02 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -651,196 +651,3 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
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 503f226fd6..dc5f3e8e73 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1020,7 +1020,8 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// 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;
}
diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m
index 8717bd09eb..df0785bf89 100644
--- a/test/SemaObjC/comptypes-1.m
+++ b/test/SemaObjC/comptypes-1.m
@@ -66,9 +66,7 @@ int main()
/* Any comparison between 'MyClass *' and anything which is not an 'id'
must generate a warning. */
- /* FIXME: GCC considers this a warning ("comparison of distinct pointer types"). */
- /* There is a corresponding FIXME in ASTContext::mergeTypes() */
- if (obj_p == obj_c) foo() ;
+ if (obj_p == obj_c) foo() ; // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'MyClass *')}}
if (obj_c == obj_cp) foo() ; // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'MyOtherClass *')}}
if (obj_cp == obj_c) foo() ; // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'MyClass *')}}
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
index faca6937cb..881fd2b555 100644
--- a/test/SemaObjC/comptypes-7.m
+++ b/test/SemaObjC/comptypes-7.m
@@ -28,7 +28,7 @@ int main()
obj = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'id'}}
obj_p = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'id<MyProtocol>'}}
- obj_p = j; // expected-warning {{incompatible type assigning 'int *', expected 'id<MyProtocol>'}}
+ obj_p = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'id<MyProtocol>'}}
obj_c = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'MyClass *'}}
obj_c = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'MyClass *'}}
@@ -42,7 +42,7 @@ int main()
i = obj_C; // expected-warning {{incompatible pointer to integer conversion assigning 'Class', expected 'int'}}
j = obj; // expected-warning {{incompatible pointer types assigning 'id', expected 'int *'}}
- j = obj_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'int *'}}
+ j = obj_p; // expected-warning {{incompatible pointer types assigning 'id<MyProtocol>', expected 'int *'}}
j = obj_c; // expected-warning {{incompatible pointer types assigning 'MyClass *', expected 'int *'}}
j = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'int *'}}
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index 8ae1338277..2043503ddf 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -27,9 +27,8 @@
@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'nextOutputStream' not found}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream];
- // GCC warns about both of these.
self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream2 *'}}
- return nextOutputStream ? nextOutputStream : self;
+ return nextOutputStream ? nextOutputStream : self; // expected-warning {{incompatible operand types ('id<DTOutputStreams>' and 'DTFilterOutputStream2 *')}}
}
@end
@@ -37,9 +36,8 @@
@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream]; // expected-warning {{method '-nextOutputStream' not found (return type defaults to 'id')}}
- // GCC warns about both of these as well (no errors).
self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream3 *'}}
- return nextOutputStream ? nextOutputStream : self;
+ return nextOutputStream ? nextOutputStream : self; // expected-warning {{incompatible operand types ('id<DTOutputStreams>' and 'DTFilterOutputStream3 *')}}
}
@end
@@ -86,7 +84,7 @@ void f4(int cond, id x, B *y) {
}
void f5(int cond, id<P0> x, C *y) {
- (cond ? x : y).intProp = 1; // expected-error {{property 'intProp' not found on object of type 'C *'}}
+ (cond ? x : y).intProp = 1; // expected-warning {{incompatible operand types ('id<P0>' and 'C *')}} expected-error {{property 'intProp' not found on object of type 'id'}}
}
void f6(int cond, C *x, D *y) {