diff options
-rw-r--r-- | AST/ASTContext.cpp | 36 | ||||
-rw-r--r-- | AST/Decl.cpp | 4 | ||||
-rw-r--r-- | Sema/SemaDeclObjC.cpp | 12 | ||||
-rw-r--r-- | include/clang/AST/DeclObjC.h | 24 | ||||
-rw-r--r-- | test/Sema/objc-comptypes-1.m | 82 |
5 files changed, 132 insertions, 26 deletions
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 6520fa920e..531b348489 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -1273,19 +1273,21 @@ bool ASTContext::ObjcQualifiedIdTypesAreCompatible(QualType lhs, // match id<P..> with an 'id' type in all cases. if (const PointerType *PT = lhs->getAsPointerType()) { QualType PointeeTy = PT->getPointeeType(); - if (isObjcIdType(PointeeTy)) + if (isObjcIdType(PointeeTy) || PointeeTy->isVoidType()) return true; } else if (const PointerType *PT = rhs->getAsPointerType()) { QualType PointeeTy = PT->getPointeeType(); - if (isObjcIdType(PointeeTy)) + if (isObjcIdType(PointeeTy) || PointeeTy->isVoidType()) return true; } ObjcQualifiedInterfaceType *lhsQI = 0; ObjcQualifiedInterfaceType *rhsQI = 0; + ObjcInterfaceDecl *lhsID = 0; + ObjcInterfaceDecl *rhsID = 0; ObjcQualifiedIdType *lhsQID = dyn_cast<ObjcQualifiedIdType>(lhs); ObjcQualifiedIdType *rhsQID = dyn_cast<ObjcQualifiedIdType>(rhs); @@ -1296,8 +1298,14 @@ bool ASTContext::ObjcQualifiedIdTypesAreCompatible(QualType lhs, rhsQI = dyn_cast<ObjcQualifiedInterfaceType>( rtype.getCanonicalType().getTypePtr()); + if (!rhsQI) { + ObjcInterfaceType *IT = dyn_cast<ObjcInterfaceType>( + rtype.getCanonicalType().getTypePtr()); + if (IT) + rhsID = IT->getDecl(); + } } - if (!rhsQI && !rhsQID) + if (!rhsQI && !rhsQID && !rhsID) return false; for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { @@ -1309,10 +1317,14 @@ bool ASTContext::ObjcQualifiedIdTypesAreCompatible(QualType lhs, numRhsProtocols = rhsQI->getNumProtocols(); rhsProtoList = rhsQI->getReferencedProtocols(); } - else { + else if (rhsQID) { numRhsProtocols = rhsQID->getNumProtocols(); rhsProtoList = rhsQID->getReferencedProtocols(); } + else { + numRhsProtocols = rhsID->getNumIntfRefProtocols(); + rhsProtoList = rhsID->getReferencedProtocols(); + } for (unsigned j = 0; j < numRhsProtocols; j++) { ObjcProtocolDecl *rhsProto = rhsProtoList[j]; if (lhsProto == rhsProto) { @@ -1331,19 +1343,31 @@ bool ASTContext::ObjcQualifiedIdTypesAreCompatible(QualType lhs, lhsQI = dyn_cast<ObjcQualifiedInterfaceType>( ltype.getCanonicalType().getTypePtr()); + if (!lhsQI) { + ObjcInterfaceType *IT = dyn_cast<ObjcInterfaceType>( + ltype.getCanonicalType().getTypePtr()); + if (IT) + lhsID = IT->getDecl(); + } } - if (!lhsQI && !lhsQID) + if (!lhsQI && !lhsQID && !lhsID) return false; + unsigned numLhsProtocols; ObjcProtocolDecl **lhsProtoList; if (lhsQI) { numLhsProtocols = lhsQI->getNumProtocols(); lhsProtoList = lhsQI->getReferencedProtocols(); } - else { + else if (lhsQID) { numLhsProtocols = lhsQID->getNumProtocols(); lhsProtoList = lhsQID->getReferencedProtocols(); } + else { + numLhsProtocols = lhsID->getNumIntfRefProtocols(); + lhsProtoList = lhsID->getReferencedProtocols(); + } + for (unsigned i =0; i < numLhsProtocols; i++) { bool match = false; ObjcProtocolDecl *lhsProto = lhsProtoList[i]; diff --git a/AST/Decl.cpp b/AST/Decl.cpp index 4310e23925..b82bc395ba 100644 --- a/AST/Decl.cpp +++ b/AST/Decl.cpp @@ -516,7 +516,7 @@ ObjcMethodDecl *ObjcProtocolDecl::lookupInstanceMethod(Selector Sel) { if (getNumReferencedProtocols() > 0) { ObjcProtocolDecl **RefPDecl = getReferencedProtocols(); - for (int i = 0; i < getNumReferencedProtocols(); i++) { + for (unsigned i = 0; i < getNumReferencedProtocols(); i++) { if ((MethodDecl = RefPDecl[i]->getInstanceMethod(Sel))) return MethodDecl; } @@ -535,7 +535,7 @@ ObjcMethodDecl *ObjcProtocolDecl::lookupClassMethod(Selector Sel) { if (getNumReferencedProtocols() > 0) { ObjcProtocolDecl **RefPDecl = getReferencedProtocols(); - for (int i = 0; i < getNumReferencedProtocols(); i++) { + for(unsigned i = 0; i < getNumReferencedProtocols(); i++) { if ((MethodDecl = RefPDecl[i]->getClassMethod(Sel))) return MethodDecl; } diff --git a/Sema/SemaDeclObjC.cpp b/Sema/SemaDeclObjC.cpp index 3f95968000..a044f2e619 100644 --- a/Sema/SemaDeclObjC.cpp +++ b/Sema/SemaDeclObjC.cpp @@ -135,7 +135,7 @@ Sema::DeclTy *Sema::ActOnStartClassInterface( Diag(ClassLoc, diag::warn_undef_protocolref, ProtocolNames[i]->getName(), ClassName->getName()); - IDecl->setIntfRefProtocols((int)i, RefPDecl); + IDecl->setIntfRefProtocols(i, RefPDecl); } IDecl->setLocEnd(EndProtoLoc); } @@ -216,7 +216,7 @@ Sema::DeclTy *Sema::ActOnStartProtocolInterface( Diag(ProtocolLoc, diag::warn_undef_protocolref, ProtoRefNames[i]->getName(), ProtocolName->getName()); - PDecl->setReferencedProtocols((int)i, RefPDecl); + PDecl->setReferencedProtocols(i, RefPDecl); } PDecl->setLocEnd(EndProtoLoc); } @@ -300,7 +300,7 @@ Sema::DeclTy *Sema::ActOnStartCategoryInterface( ProtoRefNames[i]->getName(), CategoryName->getName()); } - CDecl->setCatReferencedProtocols((int)i, RefPDecl); + CDecl->setCatReferencedProtocols(i, RefPDecl); } CDecl->setLocEnd(EndProtoLoc); } @@ -481,7 +481,7 @@ void Sema::CheckProtocolMethodDefs(ObjcProtocolDecl *PDecl, } // Check on this protocols's referenced protocols, recursively ObjcProtocolDecl** RefPDecl = PDecl->getReferencedProtocols(); - for (int i = 0; i < PDecl->getNumReferencedProtocols(); i++) + for (unsigned i = 0; i < PDecl->getNumReferencedProtocols(); i++) CheckProtocolMethodDefs(RefPDecl[i], IncompleteImpl, InsMap, ClsMap); } @@ -521,7 +521,7 @@ void Sema::ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl, // Check the protocol list for unimplemented methods in the @implementation // class. ObjcProtocolDecl** protocols = IDecl->getReferencedProtocols(); - for (int i = 0; i < IDecl->getNumIntfRefProtocols(); i++) + for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) CheckProtocolMethodDefs(protocols[i], IncompleteImpl, InsMap, ClsMap); if (IncompleteImpl) @@ -567,7 +567,7 @@ void Sema::ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl, // Check the protocol list for unimplemented methods in the @implementation // class. ObjcProtocolDecl** protocols = CatClassDecl->getReferencedProtocols(); - for (int i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) { + for (unsigned i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) { ObjcProtocolDecl* PDecl = protocols[i]; CheckProtocolMethodDefs(PDecl, IncompleteImpl, InsMap, ClsMap); } diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index cbe0912246..7b84151532 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -186,7 +186,7 @@ class ObjcInterfaceDecl : public TypeDecl { /// Protocols referenced in interface header declaration ObjcProtocolDecl **ReferencedProtocols; // Null if none - int NumReferencedProtocols; // -1 if none + unsigned NumReferencedProtocols; // 0 if none /// Ivars/NumIvars - This is a new[]'d array of pointers to Decls. ObjcIvarDecl **Ivars; // Null if not defined. @@ -217,7 +217,7 @@ public: IdentifierInfo *Id, bool FD = false, bool isInternal = false) : TypeDecl(ObjcInterface, atLoc, Id, 0), SuperClass(0), - ReferencedProtocols(0), NumReferencedProtocols(-1), Ivars(0), + ReferencedProtocols(0), NumReferencedProtocols(0), Ivars(0), NumIvars(-1), InstanceMethods(0), NumInstanceMethods(-1), ClassMethods(0), NumClassMethods(-1), @@ -239,7 +239,7 @@ public: ObjcProtocolDecl **getReferencedProtocols() const { return ReferencedProtocols; } - int getNumIntfRefProtocols() const { return NumReferencedProtocols; } + unsigned getNumIntfRefProtocols() const { return NumReferencedProtocols; } int getNumInstanceVariables() const { return NumIvars; } @@ -273,7 +273,7 @@ public: bool isForwardDecl() const { return ForwardDecl; } void setForwardDecl(bool val) { ForwardDecl = val; } - void setIntfRefProtocols(int idx, ObjcProtocolDecl *OID) { + void setIntfRefProtocols(unsigned idx, ObjcProtocolDecl *OID) { assert((idx < NumReferencedProtocols) && "index out of range"); ReferencedProtocols[idx] = OID; } @@ -394,7 +394,7 @@ private: class ObjcProtocolDecl : public NamedDecl { /// referenced protocols ObjcProtocolDecl **ReferencedProtocols; // Null if none - int NumReferencedProtocols; // -1 if none + unsigned NumReferencedProtocols; // 0 if none /// protocol instance methods ObjcMethodDecl **InstanceMethods; // Null if not defined @@ -412,7 +412,7 @@ public: ObjcProtocolDecl(SourceLocation L, unsigned numRefProtos, IdentifierInfo *Id, bool FD = false) : NamedDecl(ObjcProtocol, L, Id), - ReferencedProtocols(0), NumReferencedProtocols(-1), + ReferencedProtocols(0), NumReferencedProtocols(0), InstanceMethods(0), NumInstanceMethods(-1), ClassMethods(0), NumClassMethods(-1), isForwardProtoDecl(FD) { @@ -430,7 +430,7 @@ public: ObjcMethodDecl **clsMethods, unsigned numClsMembers, SourceLocation AtEndLoc); - void setReferencedProtocols(int idx, ObjcProtocolDecl *OID) { + void setReferencedProtocols(unsigned idx, ObjcProtocolDecl *OID) { assert((idx < NumReferencedProtocols) && "index out of range"); ReferencedProtocols[idx] = OID; } @@ -438,7 +438,7 @@ public: ObjcProtocolDecl** getReferencedProtocols() const { return ReferencedProtocols; } - int getNumReferencedProtocols() const { return NumReferencedProtocols; } + unsigned getNumReferencedProtocols() const { return NumReferencedProtocols; } int getNumInstanceMethods() const { return NumInstanceMethods; } int getNumClassMethods() const { return NumClassMethods; } @@ -587,7 +587,7 @@ class ObjcCategoryDecl : public NamedDecl { /// referenced protocols in this category ObjcProtocolDecl **ReferencedProtocols; // Null if none - int NumReferencedProtocols; // -1 if none + unsigned NumReferencedProtocols; // 0 if none /// category instance methods ObjcMethodDecl **InstanceMethods; // Null if not defined @@ -605,7 +605,7 @@ class ObjcCategoryDecl : public NamedDecl { public: ObjcCategoryDecl(SourceLocation L, unsigned numRefProtocol,IdentifierInfo *Id) : NamedDecl(ObjcCategory, L, Id), - ClassInterface(0), ReferencedProtocols(0), NumReferencedProtocols(-1), + ClassInterface(0), ReferencedProtocols(0), NumReferencedProtocols(0), InstanceMethods(0), NumInstanceMethods(-1), ClassMethods(0), NumClassMethods(-1), NextClassCategory(0) { @@ -620,7 +620,7 @@ public: ObjcInterfaceDecl *getClassInterface() const { return ClassInterface; } void setClassInterface(ObjcInterfaceDecl *IDecl) { ClassInterface = IDecl; } - void setCatReferencedProtocols(int idx, ObjcProtocolDecl *OID) { + void setCatReferencedProtocols(unsigned idx, ObjcProtocolDecl *OID) { assert((idx < NumReferencedProtocols) && "index out of range"); ReferencedProtocols[idx] = OID; } @@ -628,7 +628,7 @@ public: ObjcProtocolDecl **getReferencedProtocols() const { return ReferencedProtocols; } - int getNumReferencedProtocols() const { return NumReferencedProtocols; } + unsigned getNumReferencedProtocols() const { return NumReferencedProtocols; } int getNumInstanceMethods() const { return NumInstanceMethods; } int getNumClassMethods() const { return NumClassMethods; } diff --git a/test/Sema/objc-comptypes-1.m b/test/Sema/objc-comptypes-1.m new file mode 100644 index 0000000000..246dfa1a41 --- /dev/null +++ b/test/Sema/objc-comptypes-1.m @@ -0,0 +1,82 @@ +// RUN: clang -fsyntax-only -verify %s + +#include <objc/objc.h> + +extern void foo(); + +@protocol MyProtocol +- (void) foo; +@end + +@interface MyClass +@end + +@interface MyOtherClass <MyProtocol> +- (void) foo; +@end + +int main() +{ + id obj = nil; + id<MyProtocol> obj_p = nil; + MyClass *obj_c = nil; + MyOtherClass *obj_cp = nil; + Class obj_C = Nil; + + /* Assigning to an 'id' variable should never + generate a warning. */ + obj = obj_p; /* Ok */ + obj = obj_c; /* Ok */ + obj = obj_cp; /* Ok */ + obj = obj_C; /* Ok */ + + /* Assigning to a 'MyClass *' variable should always generate a + warning, unless done from an 'id'. */ + obj_c = obj; /* Ok */ + obj_c = obj_C; // expected-warning {{incompatible pointer types assigning 'Class' to 'MyClass *'}} + + /* Assigning to an 'id<MyProtocol>' variable should generate a + warning if done from a 'MyClass *' (which doesn't implement + MyProtocol), but not from an 'id' or from a 'MyOtherClass *' + (which implements MyProtocol). */ + obj_p = obj; /* Ok */ + obj_p = obj_c; // expected-error {{incompatible types assigning 'MyClass *' to 'id<MyProtocol>'}} + obj_p = obj_cp; /* Ok */ + obj_p = obj_C; // expected-error {{incompatible types assigning 'Class' to 'id<MyProtocol>'}} + + /* Assigning to a 'MyOtherClass *' variable should always generate + a warning, unless done from an 'id' or an 'id<MyProtocol>' (since + MyOtherClass implements MyProtocol). */ + obj_cp = obj; /* Ok */ + obj_cp = obj_p; /* Ok */ + obj_cp = obj_C; // expected-warning {{incompatible pointer types assigning 'Class' to 'MyOtherClass *'}} + + /* Any comparison involving an 'id' must be without warnings. */ + if (obj == obj_p) foo() ; /* Ok */ /*Bogus warning here in 2.95.4*/ + if (obj_p == obj) foo() ; /* Ok */ + if (obj == obj_c) foo() ; /* Ok */ + if (obj_c == obj) foo() ; /* Ok */ + if (obj == obj_cp) foo() ; /* Ok */ + if (obj_cp == obj) foo() ; /* Ok */ + if (obj == obj_C) foo() ; /* Ok */ + if (obj_C == obj) foo() ; /* Ok */ + + /* Any comparison between 'MyClass *' and anything which is not an 'id' + must generate a warning. */ + if (obj_p == obj_c) foo() ; // expected-error {{invalid operands to binary expression ('id<MyProtocol>' and 'MyClass *')}} + if (obj_c == obj_C) foo() ; // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'Class')}} + if (obj_C == obj_c) foo() ; // expected-warning {{comparison of distinct pointer types ('Class' and 'MyClass *')}} + + /* Any comparison between 'MyOtherClass *' (which implements + MyProtocol) and an 'id' implementing MyProtocol are Ok. */ + if (obj_cp == obj_p) foo() ; /* Ok */ + if (obj_p == obj_cp) foo() ; /* Ok */ + + + if (obj_p == obj_C) foo() ; // expected-error {{invalid operands to binary expression ('id<MyProtocol>' and 'Class')}} + if (obj_C == obj_p) foo() ; // expected-error {{invalid operands to binary expression ('Class' and 'id<MyProtocol>')}} + if (obj_cp == obj_C) foo() ; // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'Class')}} + if (obj_C == obj_cp) foo() ; // expected-warning {{comparison of distinct pointer types ('Class' and 'MyOtherClass *')}} + + return 0; +} |