From: Fariborz Jahanian Date: Fri, 21 Sep 2007 15:40:54 +0000 (+0000) Subject: This patch instantiates objects for forward protocols and in general handles use of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=894c57f565869b26a65436d250a9ca7a04d2abe0;p=clang This patch instantiates objects for forward protocols and in general handles use of protocols referenced in @protocol declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42191 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Decl.cpp b/AST/Decl.cpp index 4b330eeeeb..bde4b6b45b 100644 --- a/AST/Decl.cpp +++ b/AST/Decl.cpp @@ -29,6 +29,7 @@ static unsigned nInterfaceDecls = 0; static unsigned nClassDecls = 0; static unsigned nMethodDecls = 0; static unsigned nProtocolDecls = 0; +static unsigned nForwardProtocolDecls = 0; static unsigned nCategoryDecls = 0; static unsigned nIvarDecls = 0; @@ -59,6 +60,8 @@ const char *Decl::getDeclKindName() const { return "ObjcProtoMethod"; case ObjcProtocol: return "ObjcProtocol"; + case ObjcForwardProtocol: + return "ObjcForwardProtocol"; case Struct: return "Struct"; case Union: @@ -122,6 +125,9 @@ void Decl::PrintStats() { fprintf(stderr, " %d protocol decls, %d each (%d bytes)\n", nProtocolDecls, (int)sizeof(ObjcProtocolDecl), int(nProtocolDecls*sizeof(ObjcProtocolDecl))); + fprintf(stderr, " %d forward protocol decls, %d each (%d bytes)\n", + nForwardProtocolDecls, (int)sizeof(ObjcForwardProtocolDecl), + int(nForwardProtocolDecls*sizeof(ObjcForwardProtocolDecl))); fprintf(stderr, " %d category decls, %d each (%d bytes)\n", nCategoryDecls, (int)sizeof(ObjcCategoryDecl), int(nCategoryDecls*sizeof(ObjcCategoryDecl))); @@ -178,6 +184,9 @@ void Decl::addDeclKind(const Kind k) { case ObjcProtocol: nProtocolDecls++; break; + case ObjcForwardProtocol: + nForwardProtocolDecls++; + break; case ObjcCategory: nCategoryDecls++; break; diff --git a/Parse/MinimalAction.cpp b/Parse/MinimalAction.cpp index 7f1f239d16..c5be83b8fc 100644 --- a/Parse/MinimalAction.cpp +++ b/Parse/MinimalAction.cpp @@ -109,6 +109,23 @@ MinimalAction::ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc, return 0; } +/// ObjcForwardProtocolDeclaration - +/// Scope will always be top level file scope. +Action::DeclTy * +MinimalAction::ObjcForwardProtocolDeclaration(Scope *S, SourceLocation AtClassLoc, + IdentifierInfo **IdentList, unsigned NumElts) { + for (unsigned i = 0; i != NumElts; ++i) { + TypeNameInfo *TI = + new TypeNameInfo(1, IdentList[i]->getFETokenInfo()); + + IdentList[i]->setFETokenInfo(TI); + + // Remember that this needs to be removed when the scope is popped. + S->AddDecl(IdentList[i]); + } + return 0; +} + /// PopScope - When a scope is popped, if any typedefs are now out-of-scope, /// they are removed from the IdentifierInfo::FETokenInfo field. void MinimalAction::PopScope(SourceLocation Loc, Scope *S) { diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 0533660974..116c2d81b2 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -713,13 +713,13 @@ Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { IdentifierInfo *protocolName = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - if (Tok.getKind() == tok::semi) { // forward declaration. + llvm::SmallVector ProtocolRefs; + if (Tok.getKind() == tok::semi) { // forward declaration of one protocol. ConsumeToken(); - return 0; // FIXME: add protocolName + ProtocolRefs.push_back(protocolName); } if (Tok.getKind() == tok::comma) { // list of forward declarations. // Parse the list of forward declarations. - llvm::SmallVector ProtocolRefs; ProtocolRefs.push_back(protocolName); while (1) { @@ -738,10 +738,12 @@ Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) return 0; - return 0; // FIXME } + if (ProtocolRefs.size() > 0) + return Actions.ObjcForwardProtocolDeclaration(CurScope, AtLoc, + &ProtocolRefs[0], + ProtocolRefs.size()); // Last, and definitely not least, parse a protocol declaration. - llvm::SmallVector ProtocolRefs; if (Tok.getKind() == tok::less) { if (ParseObjCProtocolReferences(ProtocolRefs)) return 0; diff --git a/Sema/Sema.h b/Sema/Sema.h index 29a03d1eb2..d99b1fc12f 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -370,6 +370,11 @@ public: virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc, IdentifierInfo **IdentList, unsigned NumElts); + + virtual DeclTy *ObjcForwardProtocolDeclaration(Scope *S, + SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, + unsigned NumElts); virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl, DeclTy **allMethods, unsigned allNum); diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index f46ec42cbd..a82aea90b0 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -905,16 +905,66 @@ Sema::DeclTy *Sema::ObjcStartProtoInterface(SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs) { assert(ProtocolName && "Missing protocol identifier"); - ObjcProtocolDecl *PDecl; - - PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, ProtocolName); + ObjcProtocolDecl *PDecl = Context.getObjCProtocolDecl(ProtocolName); + if (PDecl) { + // Protocol already seen. Better be a forward protocol declaration + if (!PDecl->getIsForwardProtoDecl()) + Diag(ProtocolLoc, diag::err_duplicate_protocol_def, + ProtocolName->getName()); + else { + PDecl->setIsForwardProtoDecl(false); + PDecl->AllocReferencedProtocols(NumProtoRefs); + } + } + else { + PDecl = new ObjcProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs, + ProtocolName); + PDecl->setIsForwardProtoDecl(false); + // Chain & install the protocol decl into the identifier. + PDecl->setNext(ProtocolName->getFETokenInfo()); + ProtocolName->setFETokenInfo(PDecl); + Context.setObjCProtocolDecl(ProtocolName, PDecl); + } + + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtoRefs; i++) { + ObjcProtocolDecl* RefPDecl = Context.getObjCProtocolDecl(ProtoRefNames[i]); + if (!RefPDecl || RefPDecl->getIsForwardProtoDecl()) + Diag(ProtocolLoc, diag::err_undef_protocolref, + ProtoRefNames[i]->getName(), + ProtocolName->getName()); + PDecl->setReferencedProtocols((int)i, RefPDecl); + } - // Chain & install the protocol decl into the identifier. - PDecl->setNext(ProtocolName->getFETokenInfo()); - ProtocolName->setFETokenInfo(PDecl); return PDecl; } +/// ObjcForwardProtocolDeclaration - +/// Scope will always be top level file scope. +Action::DeclTy * +Sema::ObjcForwardProtocolDeclaration(Scope *S, SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, unsigned NumElts) { + ObjcForwardProtocolDecl *FDecl = new ObjcForwardProtocolDecl(AtProtocolLoc, + NumElts); + + for (unsigned i = 0; i != NumElts; ++i) { + ObjcProtocolDecl *PDecl; + PDecl = Context.getObjCProtocolDecl(IdentList[i]); + if (!PDecl) {// Already seen? + PDecl = new ObjcProtocolDecl(SourceLocation(), 0, IdentList[i], true); + // Chain & install the protocol decl into the identifier. + PDecl->setNext(IdentList[i]->getFETokenInfo()); + IdentList[i]->setFETokenInfo(PDecl); + Context.setObjCProtocolDecl(IdentList[i], PDecl); + } + // Remember that this needs to be removed when the scope is popped. + S->AddDecl(IdentList[i]); + + FDecl->setForwardProtocolDecl((int)i, PDecl); + } + return FDecl; +} + Sema::DeclTy *Sema::ObjcStartCatInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 0e4bab1eab..fe7cc3c003 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -38,6 +38,7 @@ class ASTContext { llvm::FoldingSet FunctionTypeProtos; llvm::DenseMap RecordLayoutInfo; llvm::DenseMap ClassNameInfo; + llvm::DenseMap ProtocolNameInfo; RecordDecl *CFConstantStringTypeDecl; public: @@ -165,6 +166,12 @@ public: ObjcInterfaceDecl* InterfaceDecl) { ClassNameInfo[ClassName] = InterfaceDecl; } + ObjcProtocolDecl* getObjCProtocolDecl(const IdentifierInfo* ProtocolName) + { return ProtocolNameInfo[ProtocolName]; } + void setObjCProtocolDecl(const IdentifierInfo* ProtocolName, + ObjcProtocolDecl* ProtocolDecl) + { ProtocolNameInfo[ProtocolName] = ProtocolDecl; } + //===--------------------------------------------------------------------===// // Type Operators //===--------------------------------------------------------------------===// diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 40607cfd4f..0ba45810b5 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -38,7 +38,7 @@ public: Function, BlockVariable, FileVariable, ParmVariable, EnumConstant, // Concrete sub-classes of TypeDecl Typedef, Struct, Union, Class, Enum, ObjcInterface, ObjcClass, ObjcMethod, - ObjcProtoMethod, ObjcProtocol, ObjcCategory, + ObjcProtoMethod, ObjcProtocol, ObjcForwardProtocol, ObjcCategory, // Concrete sub-class of Decl Field, ObjcIvar }; @@ -680,6 +680,10 @@ public: }; class ObjcProtocolDecl : public TypeDecl { + /// referenced protocols + ObjcProtocolDecl **ReferencedProtocols; // Null if none + int NumReferencedProtocols; // -1 if none + /// protocol instance methods ObjcMethodDecl **ProtoInsMethods; // Null if not defined int NumProtoInsMethods; // -1 if not defined @@ -690,20 +694,62 @@ class ObjcProtocolDecl : public TypeDecl { bool isForwardProtoDecl; // declared with @protocol. public: - ObjcProtocolDecl(SourceLocation L, IdentifierInfo *Id, bool FD = false) + ObjcProtocolDecl(SourceLocation L, unsigned numRefProtos, + IdentifierInfo *Id, bool FD = false) : TypeDecl(ObjcProtocol, L, Id, 0), + ReferencedProtocols(0), NumReferencedProtocols(-1), ProtoInsMethods(0), NumProtoInsMethods(-1), ProtoClsMethods(0), NumProtoClsMethods(-1), - isForwardProtoDecl(FD) { } - + isForwardProtoDecl(FD) { + AllocReferencedProtocols(numRefProtos); + } + void AllocReferencedProtocols(unsigned numRefProtos) { + if (numRefProtos) { + ReferencedProtocols = new ObjcProtocolDecl*[numRefProtos]; + memset(ReferencedProtocols, '\0', + numRefProtos*sizeof(ObjcProtocolDecl*)); + NumReferencedProtocols = numRefProtos; + } + } void ObjcAddProtoMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers, ObjcMethodDecl **clsMethods, unsigned numClsMembers); + + void setReferencedProtocols(int idx, ObjcProtocolDecl *OID) { + assert((idx < NumReferencedProtocols) && "index out of range"); + ReferencedProtocols[idx] = OID; + } + + + bool getIsForwardProtoDecl() const { return isForwardProtoDecl; } + void setIsForwardProtoDecl(bool val) { isForwardProtoDecl = val; } static bool classof(const Decl *D) { return D->getKind() == ObjcProtocol; } static bool classof(const ObjcProtocolDecl *D) { return true; } }; + +class ObjcForwardProtocolDecl : public TypeDecl { + ObjcProtocolDecl **ForwardProtocolDecls; // Null if not defined. + int NumForwardProtocolDecls; // -1 if not defined. + public: + ObjcForwardProtocolDecl(SourceLocation L, unsigned nElts) + : TypeDecl(ObjcForwardProtocol, L, 0, 0) { + if (nElts) { + ForwardProtocolDecls = new ObjcProtocolDecl*[nElts]; + memset(ForwardProtocolDecls, '\0', nElts*sizeof(ObjcProtocolDecl*)); + NumForwardProtocolDecls = nElts; + } + } + void setForwardProtocolDecl(int idx, ObjcProtocolDecl *OID) { + assert((idx < NumForwardProtocolDecls) && "index out of range"); + ForwardProtocolDecls[idx] = OID; + } + static bool classof(const Decl *D) { + return D->getKind() == ObjcForwardProtocol; + } + static bool classof(const ObjcForwardProtocolDecl *D) { return true; } +}; class ObjcCategoryDecl : public ScopedDecl { /// category instance methods diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 445f3bf2b8..2556b23242 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -412,7 +412,10 @@ DIAG(err_undef_superclass, ERROR, "cannot find interface declaration for '%0', superclass of '%1'") DIAG(err_duplicate_class_def, ERROR, "duplicate interface declaration for class '%0'") - +DIAG(err_undef_protocolref, ERROR, + "cannot find protocol definition for '%0', referenced by '%1'") +DIAG(err_duplicate_protocol_def, ERROR, + "duplicate protocol declaration of '%0'") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index fab3bfe73d..dca0100075 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -502,6 +502,14 @@ public: unsigned NumElts) { return 0; } + + virtual DeclTy *ObjcForwardProtocolDeclaration(Scope *S, + SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, + unsigned NumElts) { + return 0; + } + virtual void ObjCStartCategoryInterface() { // FIXME return; } @@ -548,6 +556,11 @@ public: IdentifierInfo **IdentList, unsigned NumElts); + virtual DeclTy *ObjcForwardProtocolDeclaration(Scope *S, + SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, + unsigned NumElts); + virtual DeclTy *ObjcStartClassInterface(SourceLocation AtInterafceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, diff --git a/test/Sema/protocol-test-2.m b/test/Sema/protocol-test-2.m new file mode 100644 index 0000000000..04ad3c6740 --- /dev/null +++ b/test/Sema/protocol-test-2.m @@ -0,0 +1,29 @@ +@interface INTF1 @end + +@protocol p1,p2,p3; + +@protocol p1; + +@protocol PROTO1 +- (INTF1*) meth; +@end + +@protocol PROTO2 // expected-error {{cannot find protocol definition for 'p1', referenced by 'PROTO2'}} +@end + +@protocol p1 @end + +@protocol PROTO +@end + +@protocol PROTO // expected-error {{duplicate protocol declaration of 'PROTO'}} +@end + +@protocol PROTO3 +@end + +@protocol p2 +@end + +@protocol PROTO4 // expected-error {{cannot find protocol definition for 'p3', referenced by 'PROTO4'}} +@end