]> granicus.if.org Git - clang/commitdiff
Implement cross-module declaration merging for tag declarations, so
authorDouglas Gregor <dgregor@apple.com>
Tue, 3 Jan 2012 22:46:00 +0000 (22:46 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 3 Jan 2012 22:46:00 +0000 (22:46 +0000)
that if two modules A and B both contain a declaration of a tag such
as

  struct X;

and those two modules are unrelated, the two declarations of X will be
merged into a single redeclaration chain.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147488 91177308-0d34-0410-b5e6-96231b3b80d8

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/Inputs/redecl-merge-top.h
test/Modules/redecl-merge.m

index 82f6fae4a034df0f0090714388c39d80b48b57b6..4871a3049ab9c53c8eb1f2f5e3fb5f1f9b81ffc2 100644 (file)
@@ -182,6 +182,10 @@ namespace clang {
       
       ~FindExistingResult();
       
+      /// \brief Suppress the addition of this result into the known set of
+      /// names.
+      void suppress() { AddResult = false; }
+      
       operator NamedDecl*() const { return Existing; }
       
       template<typename T>
@@ -412,20 +416,27 @@ void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) {
 }
 
 void ASTDeclReader::VisitTagDecl(TagDecl *TD) {
-  VisitRedeclarable(TD);
+  // Record the declaration -> global ID mapping.
+  Reader.DeclToID[TD] = ThisDeclID;
+    
+  RedeclarableResult Redecl = VisitRedeclarable(TD);
   VisitTypeDecl(TD);
+  
   TD->IdentifierNamespace = Record[Idx++];
   TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
   TD->setCompleteDefinition(Record[Idx++]);
   TD->setEmbeddedInDeclarator(Record[Idx++]);
   TD->setFreeStanding(Record[Idx++]);
   TD->setRBraceLoc(ReadSourceLocation(Record, Idx));
+  
   if (Record[Idx++]) { // hasExtInfo
     TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo();
     ReadQualifierInfo(*Info, Record, Idx);
     TD->TypedefNameDeclOrQualifier = Info;
   } else
     TD->setTypedefNameForAnonDecl(ReadDeclAs<TypedefNameDecl>(Record, Idx));
+
+  mergeRedeclarable(TD, Redecl);  
 }
 
 void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
@@ -1547,6 +1558,14 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
           if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
                 == Merged.end())
             Merged.push_back(Redecl.getFirstID());
+          
+          // If ExistingCanon did not come from a module file, introduce the
+          // first declaration that *does* come from a module file is in the 
+          // set of pending declaration chains, so that we merge this 
+          // declaration.
+          if (!ExistingCanon->isFromASTFile() &&
+              Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
+            Reader.PendingDeclChains.push_back(Merged[0]);
         }
       }
     }
@@ -1662,6 +1681,15 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
   if (isa<ObjCInterfaceDecl>(X) || isa<ObjCProtocolDecl>(X))
     return true;
   
+  // Compatible tags match.
+  if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
+    TagDecl *TagY = cast<TagDecl>(Y);
+    if ((TagX->getTagKind() == TagY->getTagKind()) ||
+        ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class)&&
+         (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class)))
+      return true;
+  }
+        
   // FIXME: Many other cases to implement.
   return false;
 }
@@ -1679,13 +1707,21 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
 }
 
 ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
+  DeclarationName Name = D->getDeclName();
+  if (!Name) {
+    // Don't bother trying to find unnamed declarations.
+    FindExistingResult Result(Reader, D, /*Existing=*/0);
+    Result.suppress();
+    return Result;
+  }
+  
   DeclContext *DC = D->getDeclContext()->getRedeclContext();
   if (!DC->isFileContext())
     return FindExistingResult(Reader);
   
   if (DC->isTranslationUnit() && Reader.SemaObj) {
     IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
-    for (IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), 
+    for (IdentifierResolver::iterator I = IdResolver.begin(Name), 
                                    IEnd = IdResolver.end();
          I != IEnd; ++I) {
       if (isSameEntity(*I, D))
index a054cd20596ac453f344bed2614bdb6ca8657f1f..4e52a6724783c057776fc6bff01b27cc4b15ef14 100644 (file)
@@ -13,6 +13,9 @@
 
 @protocol P1;
 
+struct S1;
+struct S3;
+
 void refers_to_C4(C4*);
 
 #ifdef __cplusplus
index 82146f7ed5036f6f572b96c137541725f4e290f6..b21271b14621ace38c5479496442490925a24fd8 100644 (file)
 - (void)protoMethod2;
 @end
 
+struct S1;
+struct S2 {
+  int field;
+};
+
+struct S1 *produce_S1(void);
+void consume_S2(struct S2*);
+
 // Test declarations in different modules with no common initial
 // declaration.
 @class C;
@@ -39,6 +47,15 @@ struct explicit_struct;
 
 @protocol P3;
 
+struct S3;
+struct S3;
+struct S4 {
+  int field;
+};
+
+struct S3 *produce_S3(void);
+void consume_S4(struct S4*);
+
 #ifdef __cplusplus
 template<typename T> class Vector;
 
index b6dfe2f53c94fe6a7faa6769c7c50066c76f3476..686a96228a19f655a7573ff73e1e792d3f421efb 100644 (file)
 
 @protocol P2;
 
+struct S1;
+struct S2;
+
+void consume_S1(struct S1*);
+struct S2 *produce_S2(void);
+
 // Test declarations in different modules with no common initial
 // declaration.
 @class C;
@@ -47,6 +53,12 @@ struct explicit_struct;
 @protocol P3;
 @protocol P3;
 
+struct S3;
+struct S4;
+
+void consume_S3(struct S3*);
+struct S4 *produce_S4(void);
+
 #ifdef __cplusplus
 template<typename T> class Vector { 
 public:
index 64c0c925464139b22da6d52ae0a2aeb121b10278..519254ca22139288efcb5146288240a3a69a76df 100644 (file)
 @protocol P2;
 @protocol P2;
 
+struct S1;
+struct S2;
+struct S2;
+
 #ifdef __cplusplus
 template<typename T> class Vector;
 #endif
index dfbc25fe9e7bfbb6f47c7b5cfb71eb0760b10ea3..c0e83e8a86495bfbd14a962b897e636ca5d4a4ca 100644 (file)
@@ -32,6 +32,29 @@ void testProtoMerge(id<P1> p1, id<P2> p2) {
   [p2 protoMethod2];
 }
 
+struct S1 {
+  int s1_field;
+};
+
+struct S3 {
+  int s3_field;
+};
+
+void testTagMerge() {
+  consume_S1(produce_S1());
+  struct S2 s2;
+  s2.field = 0;
+  consume_S2(produce_S2());
+  struct S1 s1;
+  s1.s1_field = 0;
+  consume_S3(produce_S3());
+  struct S4 s4;
+  s4.field = 0;
+  consume_S4(produce_S4());
+  struct S3 s3;
+  s3.s3_field = 0;
+}
+
 // Test redeclarations of entities in explicit submodules, to make
 // sure we're maintaining the declaration chains even when normal name
 // lookup can't see what we're looking for.