]> granicus.if.org Git - clang/commitdiff
Implement declaration merging for Objective-C protocols across
authorDouglas Gregor <dgregor@apple.com>
Sun, 1 Jan 2012 21:47:52 +0000 (21:47 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 1 Jan 2012 21:47:52 +0000 (21:47 +0000)
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

include/clang/Serialization/ASTReader.h
lib/Serialization/ASTReaderDecl.cpp
test/Modules/Inputs/redecl-merge-bottom.h
test/Modules/Inputs/redecl-merge-left.h
test/Modules/Inputs/redecl-merge-right.h
test/Modules/redecl-merge.m

index 1595a0ef61f0bd032b43da5e9675ed25845cb7fb..f808b962e113876fec77357dbd8376307cb4c2f5 100644 (file)
@@ -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> >
index 1df67f22ab533fdd5822f37a3e5b77963bce4640..12436c5c4fe73bdb9ebc35357ae9ccb697a4b8d3 100644 (file)
@@ -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.
index b3cc74b655cef8af44ff17b738b13b346f6b8507..26a1ba5ab176e668f857974e27dd851f77de4bbe 100644 (file)
@@ -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;
index 2d77badeea728d480002955d79804c21cda8ee9e..4ea1e70e8e64eab780cac8f51c2de71212d0993e 100644 (file)
@@ -35,6 +35,10 @@ int *explicit_func(void);
 
 struct explicit_struct;
 
+@protocol P3, P4;
+
+@protocol P3;
+
 #ifdef __cplusplus
 template<typename T> class Vector;
 
index c5e35b1d63b6ba17d852da1fdcd69eb563386fbf..82051d46f935b0907b433ea757c644f1bd8595e5 100644 (file)
@@ -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:
index d7927396cab9a225db18a1b11105ee8244ed73c3..4ea982b50fee9d8e3dc054b303a051b6c76f4149 100644 (file)
@@ -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;