From: Douglas Gregor Date: Sun, 1 Jan 2012 21:47:52 +0000 (+0000) Subject: Implement declaration merging for Objective-C protocols across X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dba9361891ab147b6ea658c1834bc1d660f5226b;p=clang Implement declaration merging for Objective-C protocols across multiple, disjoint modules. There is far too much duplicating with the ObjCInterfaceDecl case here, which I'll eliminate shortly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147417 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 1595a0ef61..f808b962e1 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -677,9 +677,9 @@ private: /// \brief Reverse mapping from declarations to their global declaration IDs. /// - /// FIXME: This data structure is currently only used for ObjCInterfaceDecls, - /// support declaration merging. If we must have this for other declarations, - /// allocate it along with the Decl itself. + /// FIXME: This data structure is currently only used for ObjCInterfaceDecls + /// and ObjCProtocolDecls to support declaration merging. If we must have + /// this for other declarations, allocate it along with the Decl itself. llvm::DenseMap DeclToID; typedef llvm::DenseMap > diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 1df67f22ab..12436c5c4f 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -759,12 +759,54 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) { } void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { - VisitRedeclarable(PD); + // Record the declaration -> global ID mapping. + Reader.DeclToID[PD] = ThisDeclID; + + RedeclarableResult Redecl = VisitRedeclarable(PD); VisitObjCContainerDecl(PD); PD->InitiallyForwardDecl = Record[Idx++]; PD->isForwardProtoDecl = Record[Idx++]; PD->setLocEnd(ReadSourceLocation(Record, Idx)); + // Determine whether we need to merge this declaration with another @protocol + // with the same name. + // FIXME: Not needed unless the module file graph is a DAG. + if (FindExistingResult ExistingRes = findExisting(PD)) { + if (ObjCProtocolDecl *Existing = ExistingRes) { + ObjCProtocolDecl *ExistingCanon = Existing->getCanonicalDecl(); + ObjCProtocolDecl *PDCanon = PD->getCanonicalDecl(); + if (ExistingCanon != PDCanon) { + // Have our redeclaration link point back at the canonical declaration + // of the existing declaration, so that this declaration has the + // appropriate canonical declaration. + PD->RedeclLink = ObjCProtocolDecl::PreviousDeclLink(ExistingCanon); + + // Don't introduce IDCanon into the set of pending declaration chains. + Redecl.suppress(); + + // Introduce ExistingCanon into the set of pending declaration chains, + // if in fact it came from a module file. + if (ExistingCanon->isFromASTFile()) { + GlobalDeclID ExistingCanonID = Reader.DeclToID[ExistingCanon]; + assert(ExistingCanonID && "Unrecorded canonical declaration ID?"); + if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID)) + Reader.PendingDeclChains.push_back(ExistingCanonID); + } + + // If this declaration was the canonical declaration, make a note of + // that. We accept the linear algorithm here because the number of + // unique canonical declarations of an entity should always be tiny. + if (PDCanon == PD) { + SmallVectorImpl &Merged = Reader.MergedDecls[ExistingCanon]; + if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID()) + == Merged.end()) + Merged.push_back(Redecl.getFirstID()); + } + } + } + } + + ObjCProtocolDecl *Def = ReadDeclAs(Record, Idx); if (PD == Def) { // Read the definition. @@ -1645,8 +1687,8 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { Y->getDeclContext()->getRedeclContext())) return false; - // Objective-C classes with the same name always match. - if (isa(X)) + // Objective-C classes and protocols with the same name always match. + if (isa(X) || isa(X)) return true; // FIXME: Many other cases to implement. diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h index b3cc74b655..26a1ba5ab1 100644 --- a/test/Modules/Inputs/redecl-merge-bottom.h +++ b/test/Modules/Inputs/redecl-merge-bottom.h @@ -2,6 +2,9 @@ __import_module__ redecl_merge_left; @class C4; @class C4; +@protocol P4; +@protocol P4; +@protocol P4; __import_module__ redecl_merge_right; @class B; diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h index 2d77badeea..4ea1e70e8e 100644 --- a/test/Modules/Inputs/redecl-merge-left.h +++ b/test/Modules/Inputs/redecl-merge-left.h @@ -35,6 +35,10 @@ int *explicit_func(void); struct explicit_struct; +@protocol P3, P4; + +@protocol P3; + #ifdef __cplusplus template class Vector; diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h index c5e35b1d63..82051d46f9 100644 --- a/test/Modules/Inputs/redecl-merge-right.h +++ b/test/Modules/Inputs/redecl-merge-right.h @@ -42,6 +42,11 @@ int *explicit_func(void); struct explicit_struct; +@protocol P4, P3; +@protocol P3; +@protocol P3; +@protocol P3; + #ifdef __cplusplus template class Vector { public: diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m index d7927396ca..4ea982b50f 100644 --- a/test/Modules/redecl-merge.m +++ b/test/Modules/redecl-merge.m @@ -6,6 +6,7 @@ @class C3; __import_module__ redecl_merge_left; +@protocol P4; @class C3; @class C3; __import_module__ redecl_merge_right; @@ -83,6 +84,13 @@ void g(A *a) { [a init]; } +@protocol P3 +- (void)p3_method; +@end + +id p4; +id p3; + #ifdef __cplusplus void testVector() { Vector vec_int;