]> granicus.if.org Git - clang/commitdiff
Implement redeclaration merging for namespaces defined in distinct
authorDouglas Gregor <dgregor@apple.com>
Mon, 9 Jan 2012 17:30:44 +0000 (17:30 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 9 Jan 2012 17:30:44 +0000 (17:30 +0000)
modules. Teach name lookup into namespaces to search in each of the
merged DeclContexts as well as the (now-primary) DeclContext. This
supports the common case where two different modules put something
into the same namespace.

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

include/clang/AST/DeclBase.h
lib/AST/DeclBase.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
test/Modules/Inputs/namespaces-left.h
test/Modules/Inputs/namespaces-right.h
test/Modules/namespaces.cpp

index b84ac85082e15e9cc57aa167421708bab1813d60..2964d8cf0acb854967e5b63c6eab7b4f30c34f39 100644 (file)
@@ -514,6 +514,12 @@ protected:
     NextInContextAndBits.setInt(Bits);
   }
 
+  /// \brief Set the owning module ID.
+  void setOwningModuleID(unsigned ID) {
+    assert(isFromASTFile() && "Only works on a deserialized declaration");
+    *((unsigned*)this - 2) = ID;
+  }
+  
 public:
   
   /// \brief Determine the availability of the given declaration.
@@ -573,7 +579,16 @@ public:
       return *((const unsigned*)this - 1);
     return 0;
   }
-              
+  
+  /// \brief Retrieve the global ID of the module that owns this particular
+  /// declaration.
+  unsigned getOwningModuleID() const {
+    if (isFromASTFile())
+      return *((const unsigned*)this - 2);
+    
+    return 0;
+  }
+  
   unsigned getIdentifierNamespace() const {
     return IdentifierNamespace;
   }
index 0312cfbc4abebee32e09bbf5e4dfdb86638a0473..6a508dfcbe9fce862430457ede0dc4e79cd98d50 100644 (file)
@@ -45,14 +45,17 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
                                      unsigned ID,
                                      unsigned Size) {
   // Allocate an extra 8 bytes worth of storage, which ensures that the
-  // resulting pointer will still be 8-byte aligned. At present, we're only
-  // using the latter 4 bytes of this storage.
+  // resulting pointer will still be 8-byte aligned. 
   void *Start = Context.Allocate(Size + 8);
   void *Result = (char*)Start + 8;
   
-  // Store the global declaration ID 
-  unsigned *IDPtr = (unsigned*)Result - 1;
-  *IDPtr = ID;
+  unsigned *PrefixPtr = (unsigned *)Result - 2;
+  
+  // Zero out the first 4 bytes; this is used to store the owning module ID.
+  PrefixPtr[0] = 0;
+  
+  // Store the global declaration ID in the second 4 bytes.
+  PrefixPtr[1] = ID;
   
   return Result;
 }
index df158599ded3ae7ba5bb177b534735d838fc27a7..fa21bf5fdbfa148e1faf2fe2b52c56adc880fa9a 100644 (file)
@@ -4808,15 +4808,17 @@ namespace {
   /// declaration context.
   class DeclContextNameLookupVisitor {
     ASTReader &Reader;
+    llvm::SmallVectorImpl<const DeclContext *> &Contexts;
     const DeclContext *DC;
     DeclarationName Name;
     SmallVectorImpl<NamedDecl *> &Decls;
 
   public:
     DeclContextNameLookupVisitor(ASTReader &Reader, 
-                                 const DeclContext *DC, DeclarationName Name,
+                                 SmallVectorImpl<const DeclContext *> &Contexts, 
+                                 DeclarationName Name,
                                  SmallVectorImpl<NamedDecl *> &Decls)
-      : Reader(Reader), DC(DC), Name(Name), Decls(Decls) { }
+      : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
 
     static bool visit(ModuleFile &M, void *UserData) {
       DeclContextNameLookupVisitor *This
@@ -4824,11 +4826,20 @@ namespace {
 
       // Check whether we have any visible declaration information for
       // this context in this module.
-      ModuleFile::DeclContextInfosMap::iterator Info
-        = M.DeclContextInfos.find(This->DC);
-      if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
-        return false;
+      ModuleFile::DeclContextInfosMap::iterator Info;
+      bool FoundInfo = false;
+      for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
+        Info = M.DeclContextInfos.find(This->Contexts[I]);
+        if (Info != M.DeclContextInfos.end() && 
+            Info->second.NameLookupTableData) {
+          FoundInfo = true;
+          break;
+        }
+      }
 
+      if (!FoundInfo)
+        return false;
+      
       // Look for this name within this module.
       ASTDeclContextNameLookupTable *LookupTable =
         (ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData;
@@ -4870,7 +4881,24 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
                                       DeclContext::lookup_iterator(0));
 
   SmallVector<NamedDecl *, 64> Decls;
-  DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls);
+  
+  // Compute the declaration contexts we need to look into. Multiple such
+  // declaration contexts occur when two declaration contexts from disjoint
+  // modules get merged, e.g., when two namespaces with the same name are 
+  // independently defined in separate modules.
+  SmallVector<const DeclContext *, 2> Contexts;
+  Contexts.push_back(DC);
+  
+  if (DC->isNamespace()) {
+    MergedDeclsMap::iterator Merged
+      = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+    if (Merged != MergedDecls.end()) {
+      for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+        Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+    }
+  }
+  
+  DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
   ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
   ++NumVisibleDeclContextsRead;
   SetExternalVisibleDeclsForName(DC, Name, Decls);
index 56e2d085e383366e63b7a381c4e8138140838b59..ffd768a94d287865e8a646b500d7fcefb346e113 100644 (file)
@@ -369,6 +369,9 @@ void ASTDeclReader::VisitDecl(Decl *D) {
   // Determine whether this declaration is part of a (sub)module. If so, it
   // may not yet be visible.
   if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
+    // Store the owning submodule ID in the declaration.
+    D->setOwningModuleID(SubmoduleID);
+    
     // Module-private declarations are never visible, so there is no work to do.
     if (!D->isModulePrivate()) {
       if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
@@ -972,7 +975,8 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
   D->setInline(Record[Idx++]);
   D->LocStart = ReadSourceLocation(Record, Idx);
   D->RBraceLoc = ReadSourceLocation(Record, Idx);
-  
+  mergeRedeclarable(D, Redecl);
+
   if (Redecl.getFirstID() == ThisDeclID) {
     // FIXME: If there's already an anonymous namespace, do we merge it with
     // this one? Or do we, when loading modules, just forget about anonymous
@@ -1232,7 +1236,7 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   RedeclKind Kind = (RedeclKind)Record[Idx++];
   
   // Determine the first declaration ID.
-  DeclID FirstDeclID;
+  DeclID FirstDeclID = 0;
   switch (Kind) {
   case FirstDeclaration: {
     FirstDeclID = ThisDeclID;
@@ -1489,7 +1493,7 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
   enum RedeclKind { FirstDeclaration = 0, FirstInFile, PointsToPrevious };
   RedeclKind Kind = (RedeclKind)Record[Idx++];
   
-  DeclID FirstDeclID;
+  DeclID FirstDeclID = 0;
   switch (Kind) {
   case FirstDeclaration:
     FirstDeclID = ThisDeclID;
@@ -1545,6 +1549,13 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
         D->RedeclLink 
           = typename Redeclarable<T>::PreviousDeclLink(ExistingCanon);
         
+        // When we merge a namespace, update its pointer to the first namespace.
+        if (NamespaceDecl *Namespace
+              = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+          Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+            static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+        }
+        
         // Don't introduce DCanon into the set of pending declaration chains.
         Redecl.suppress();
         
@@ -1719,6 +1730,12 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
       VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
   }
   
+  // Namespaces with the same name and inlinedness match.
+  if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
+    NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
+    return NamespaceX->isInline() == NamespaceY->isInline();
+  }
+      
   // FIXME: Many other cases to implement.
   return false;
 }
index 85e6d7dc6077ae39fdd5be214649391869ec4625..6835cda0c4f52acaf9bd7e9ff97ffc0ab0719f54 100644 (file)
@@ -9,3 +9,19 @@ namespace N1 {
 namespace N2 { 
   float& f(float);
 }
+
+
+
+
+
+namespace N5 {
+  int &f(int);
+}
+
+namespace N6 {
+  int &f(int);
+}
+
+namespace N7 {
+  int &f(int);
+}
index 23c88bdbe9bcc422846d4755b8038cae9ac1036c..0afef073c31cea14f00628c232af1883040086e8 100644 (file)
@@ -16,3 +16,14 @@ namespace N3 {
   double& f(double);
 }
 
+namespace N5 {
+  double &f(double);
+}
+
+namespace N6 {
+  double &f(double);
+}
+
+namespace N7 {
+  double &f(double);
+}
index 75557ba4c14615680595b23b04bd5c6a71a54f84..e1a8d6e8b09c81cb33d031630a8ea97bf64a9205 100644 (file)
@@ -1,6 +1,10 @@
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify
 
+namespace N6 {
+  char &f(char);
+}
+
 @import namespaces_left;
 @import namespaces_right;
 
@@ -13,3 +17,20 @@ void test() {
   double &dr1 = N2::f(1.0);
   double &dr2 = N3::f(1.0);
 }
+
+// Test namespaces merged without a common first declaration.
+namespace N5 {
+  char &f(char);
+}
+
+void testMerged() {
+  int &ir1 = N5::f(17);
+  int &ir2 = N6::f(17);
+  int &ir3 = N7::f(17);
+  double &fr1 = N5::f(1.0);
+  double &fr2 = N6::f(1.0);
+  double &fr3 = N7::f(1.0);
+  char &cr1 = N5::f('a');
+  char &cr2 = N6::f('b');
+}
+