forked from OSchip/llvm-project
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. llvm-svn: 76830
This commit is contained in:
parent
fef8db605d
commit
8e6aee5821
|
@ -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,
|
||||
|
|
|
@ -3023,43 +3023,219 @@ static bool areCompatVectorTypes(const VectorType *LHS,
|
|||
LHS->getNumElements() == RHS->getNumElements();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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 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 = 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;
|
||||
}
|
||||
|
||||
/// 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())
|
||||
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 qualified builtin types.
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!RHSImplementsProtocol)
|
||||
return false;
|
||||
}
|
||||
// The RHS implements all protocols listed on the LHS.
|
||||
return true;
|
||||
}
|
||||
return canAssignObjCInterfaces(LHS, RHS);
|
||||
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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 *')}}
|
||||
|
|
|
@ -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 *'}}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue