diff options
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 6 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 48 | ||||
-rw-r--r-- | test/Modules/Inputs/redecl-merge-bottom.h | 3 | ||||
-rw-r--r-- | test/Modules/Inputs/redecl-merge-left.h | 4 | ||||
-rw-r--r-- | test/Modules/Inputs/redecl-merge-right.h | 5 | ||||
-rw-r--r-- | test/Modules/redecl-merge.m | 8 |
6 files changed, 68 insertions, 6 deletions
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<Decl *, serialization::GlobalDeclID> DeclToID; typedef llvm::DenseMap<Decl *, llvm::SmallVector<serialization::DeclID, 2> > 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<DeclID> &Merged = Reader.MergedDecls[ExistingCanon]; + if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID()) + == Merged.end()) + Merged.push_back(Redecl.getFirstID()); + } + } + } + } + + ObjCProtocolDecl *Def = ReadDeclAs<ObjCProtocolDecl>(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<ObjCInterfaceDecl>(X)) + // Objective-C classes and protocols with the same name always match. + if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(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<typename T> 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<typename T> 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> p4; +id<P3> p3; + #ifdef __cplusplus void testVector() { Vector<int> vec_int; |