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:
Steve Naroff 2009-07-23 01:01:38 +00:00
parent fef8db605d
commit 8e6aee5821
10 changed files with 221 additions and 254 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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.

View File

@ -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)

View File

@ -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()) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 *')}}

View File

@ -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 *'}}

View File

@ -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) {