aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AST/ASTContext.cpp36
-rw-r--r--AST/Decl.cpp4
-rw-r--r--Sema/SemaDeclObjC.cpp12
-rw-r--r--include/clang/AST/DeclObjC.h24
-rw-r--r--test/Sema/objc-comptypes-1.m82
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;
+}