aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AST/Decl.cpp13
-rw-r--r--Sema/Sema.h4
-rw-r--r--Sema/SemaDecl.cpp61
-rw-r--r--include/clang/AST/Decl.h7
-rw-r--r--include/clang/Basic/DiagnosticKinds.def7
-rw-r--r--include/clang/Parse/Action.h4
-rw-r--r--test/Sema/conflicting-ivar-test-1.m84
7 files changed, 176 insertions, 4 deletions
diff --git a/AST/Decl.cpp b/AST/Decl.cpp
index c0a77a2faa..83762e9465 100644
--- a/AST/Decl.cpp
+++ b/AST/Decl.cpp
@@ -294,6 +294,19 @@ void ObjcInterfaceDecl::ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars,
}
}
+/// ObjcAddInstanceVariablesToClassImpl - Checks for correctness of Instance
+/// Variables (Ivars) relative to what declared in @implementation;s class.
+/// Ivars into ObjcImplementationDecl's fields.
+///
+void ObjcImplementationDecl::ObjcAddInstanceVariablesToClassImpl(
+ ObjcIvarDecl **ivars, unsigned numIvars) {
+ NumIvars = numIvars;
+ if (numIvars) {
+ Ivars = new ObjcIvarDecl*[numIvars];
+ memcpy(Ivars, ivars, numIvars*sizeof(ObjcIvarDecl*));
+ }
+}
+
/// addObjcMethods - Insert instance and methods declarations into
/// ObjcInterfaceDecl's InsMethods and ClsMethods fields.
///
diff --git a/Sema/Sema.h b/Sema/Sema.h
index 0891c66453..bb83b0e6ae 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -386,6 +386,10 @@ public:
virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl,
DeclTy **allMethods, unsigned allNum);
+
+ virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
+ DeclTy **Fields, unsigned NumFields);
+
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType,
ObjcKeywordDecl *Keywords, unsigned NumKeywords,
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 5470eb456b..1fb4142796 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -1129,6 +1129,51 @@ Sema::DeclTy *Sema::ObjcStartClassImplementation(Scope *S,
return IMPDecl;
}
+void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
+ DeclTy **Fields, unsigned numIvars) {
+ ObjcInterfaceDecl* IDecl =
+ cast<ObjcInterfaceDecl>(static_cast<Decl*>(ClassDecl));
+ assert(IDecl && "missing named interface class decl");
+ ObjcIvarDecl** ivars = reinterpret_cast<ObjcIvarDecl**>(Fields);
+ assert(ivars && "missing @implementation ivars");
+
+ // Check interface's Ivar list against those in the implementation.
+ // names and types must match.
+ //
+ ObjcIvarDecl** IntfIvars = IDecl->getIntfDeclIvars();
+ int IntfNumIvars = IDecl->getIntfDeclNumIvars();
+ unsigned j = 0;
+ bool err = false;
+ while (numIvars > 0 && IntfNumIvars > 0) {
+ ObjcIvarDecl* ImplIvar = ivars[j];
+ ObjcIvarDecl* ClsIvar = IntfIvars[j++];
+ assert (ImplIvar && "missing implementation ivar");
+ assert (ClsIvar && "missing class ivar");
+ if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) {
+ Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type,
+ ImplIvar->getIdentifier()->getName());
+ Diag(ClsIvar->getLocation(), diag::err_previous_definition,
+ ClsIvar->getIdentifier()->getName());
+ }
+ // TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed
+ // as error.
+ else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
+ Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name,
+ ImplIvar->getIdentifier()->getName());
+ Diag(ClsIvar->getLocation(), diag::err_previous_definition,
+ ClsIvar->getIdentifier()->getName());
+ err = true;
+ break;
+ }
+ --numIvars;
+ --IntfNumIvars;
+ }
+ if (!err && (numIvars > 0 || IntfNumIvars > 0))
+ Diag(numIvars > 0 ? ivars[j]->getLocation() : IntfIvars[j]->getLocation(),
+ diag::err_inconsistant_ivar);
+
+}
+
/// ObjcClassDeclaration -
/// Scope will always be top level file scope.
Action::DeclTy *
@@ -1463,8 +1508,20 @@ void Sema::ActOnFields(SourceLocation RecLoc, DeclTy *RecDecl,
else {
ObjcIvarDecl **ClsFields =
reinterpret_cast<ObjcIvarDecl**>(&RecFields[0]);
- cast<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl))->
- ObjcAddInstanceVariablesToClass(ClsFields, RecFields.size());
+ if (isa<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl)))
+ cast<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl))->
+ ObjcAddInstanceVariablesToClass(ClsFields, RecFields.size());
+ else if (isa<ObjcImplementationDecl>(static_cast<Decl*>(RecDecl))) {
+ ObjcImplementationDecl* IMPDecl =
+ cast<ObjcImplementationDecl>(static_cast<Decl*>(RecDecl));
+ assert(IMPDecl && "ActOnFields - missing ObjcImplementationDecl");
+ IMPDecl->ObjcAddInstanceVariablesToClassImpl(ClsFields, RecFields.size());
+ ObjcInterfaceDecl* IDecl =
+ Context.getObjCInterfaceDecl(IMPDecl->getIdentifier());
+ if (IDecl)
+ ActOnImpleIvarVsClassIvars(static_cast<DeclTy*>(IDecl),
+ reinterpret_cast<DeclTy**>(&RecFields[0]), RecFields.size());
+ }
}
}
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 7cb370b41c..b420c1da81 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -587,6 +587,9 @@ public:
NumIntfRefProtocols = numRefProtos;
}
}
+ ObjcIvarDecl **getIntfDeclIvars() const { return Ivars; }
+ int getIntfDeclNumIvars() const { return NumIvars; }
+
void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars,
unsigned numIvars);
@@ -883,8 +886,8 @@ class ObjcImplementationDecl : public TypeDecl {
Ivars(0), NumIvars(-1),
InsMethods(0), NumInsMethods(-1), ClsMethods(0), NumClsMethods(-1) {}
- void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars,
- unsigned numIvars);
+ void ObjcAddInstanceVariablesToClassImpl(ObjcIvarDecl **ivars,
+ unsigned numIvars);
void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
ObjcMethodDecl **clsMethods, unsigned numClsMembers);
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index bd41546cd3..d77e6b4d24 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -426,6 +426,13 @@ DIAG(err_dup_implementation_class, ERROR,
"reimplementation of class '%0'")
DIAG(err_conflicting_super_class, ERROR,
"conflicting super class name '%0'")
+DIAG(err_conflicting_ivar_name, ERROR,
+ "conflicting instance variable name '%0'")
+DIAG(err_inconsistant_ivar, ERROR,
+ "inconsistent instance variable specification")
+DIAG(err_conflicting_ivar_type, ERROR,
+ "conflicting instance variable type")
+
//===----------------------------------------------------------------------===//
// Semantic Analysis
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index fe902fc00f..bc14226bec 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -448,6 +448,10 @@ public:
DeclTy **allMethods, unsigned allNum) {
return;
}
+ virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
+ DeclTy **Fields, unsigned NumFields) {
+ return;
+ }
virtual DeclTy *ObjcStartProtoInterface(Scope* S,
SourceLocation AtProtoInterfaceLoc,
IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
diff --git a/test/Sema/conflicting-ivar-test-1.m b/test/Sema/conflicting-ivar-test-1.m
new file mode 100644
index 0000000000..e08da34bc2
--- /dev/null
+++ b/test/Sema/conflicting-ivar-test-1.m
@@ -0,0 +1,84 @@
+@interface INTF
+{
+@public
+ int IVAR; // expected-error {{previous definition is here}}
+}
+@end
+
+@implementation INTF
+{
+@private
+
+ int XIVAR; // expected-error {{conflicting instance variable name 'XIVAR'}}
+}
+@end
+
+
+
+@interface INTF1
+{
+@public
+ int IVAR;
+ int IVAR1; // expected-error {{inconsistent instance variable specification}}
+}
+@end
+
+@implementation INTF1
+{
+@private
+
+ int IVAR;
+}
+@end
+
+
+@interface INTF2
+{
+@public
+ int IVAR;
+}
+@end
+
+@implementation INTF2
+{
+@private
+
+ int IVAR;
+ int IVAR1; // expected-error {{inconsistent instance variable specification}}
+}
+@end
+
+
+@interface INTF3
+{
+@public
+ int IVAR; // expected-error {{previous definition is here}}
+}
+@end
+
+@implementation INTF3
+{
+@private
+
+ short IVAR; // expected-error {{conflicting instance variable type}}
+}
+@end
+
+@implementation INTF4 // expected-warning {{cannot find interface declaration for 'INTF4'}}
+{
+@private
+
+ short IVAR;
+}
+@end
+
+@interface INTF5
+{
+ char * ch;
+}
+@end
+
+@implementation INTF5
+{
+}
+@end