aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Serialization/ASTReader.h6
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp48
-rw-r--r--test/Modules/Inputs/redecl-merge-bottom.h3
-rw-r--r--test/Modules/Inputs/redecl-merge-left.h4
-rw-r--r--test/Modules/Inputs/redecl-merge-right.h5
-rw-r--r--test/Modules/redecl-merge.m8
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;