]> granicus.if.org Git - clang/commitdiff
Implement name hiding for declarations deserialized from a non-visible
authorDouglas Gregor <dgregor@apple.com>
Thu, 1 Dec 2011 22:20:10 +0000 (22:20 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 1 Dec 2011 22:20:10 +0000 (22:20 +0000)
module. When that module becomes visible, so do those declarations.

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

12 files changed:
include/clang/AST/DeclBase.h
include/clang/Serialization/ASTReader.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/submodules/hash_map.h [new file with mode: 0644]
test/Modules/Inputs/submodules/module.map
test/Modules/Inputs/submodules/vector.h
test/Modules/auto-module-import.c
test/Modules/diamond.c
test/Modules/submodules-preprocess.cpp [new file with mode: 0644]
test/Modules/submodules.cpp

index 313cf606b88dd94e63a5fa84595de7779a8e2481..ab36054969b8b757936f18b0e4a0d384d6ed4b75 100644 (file)
@@ -278,6 +278,7 @@ protected:
 
   friend class ASTDeclWriter;
   friend class ASTDeclReader;
+  friend class ASTReader;
 
 private:
   void CheckAccessDeclContext() const;
index 3f66eb51183db2c7839e9fe344bd0628a35f3f14..bbcead091145e60c6d5d0448f6c92f90ff547660 100644 (file)
@@ -383,6 +383,15 @@ private:
   /// global submodule ID to produce a local ID.
   GlobalSubmoduleMapType GlobalSubmoduleMap;
 
+  /// \brief A set of hidden declarations.
+  typedef llvm::SmallVector<Decl *, 2> HiddenNames;
+  
+  typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType;
+
+  /// \brief A mapping from each of the hidden submodules to the deserialized
+  /// declarations in that submodule that could be made visible.
+  HiddenNamesMapType HiddenNamesMap;
+  
   /// \brief A vector containing selectors that have already been loaded.
   ///
   /// This vector is indexed by the Selector ID (-1). NULL selector
@@ -813,6 +822,9 @@ public:
   void makeModuleVisible(Module *Mod, 
                          Module::NameVisibilityKind NameVisibility);
   
+  /// \brief Make the names within this set of hidden names visible.
+  void makeNamesVisible(const HiddenNames &Names);
+  
   /// \brief Set the AST callbacks listener.
   void setListener(ASTReaderListener *listener) {
     Listener.reset(listener);
@@ -829,6 +841,13 @@ public:
     ModuleMgr.addInMemoryBuffer(FileName, Buffer);
   }
 
+  /// \brief Finalizes the AST reader's state before writing an AST file to
+  /// disk.
+  ///
+  /// This operation may undo temporary state in the AST that should not be
+  /// emitted.
+  void finalizeForWriting();
+
   /// \brief Retrieve the module manager.
   ModuleManager &getModuleManager() { return ModuleMgr; }
 
index 258baebc05cfbf8bc0ed10135aff12b119cf6775..a083e24e9e35eebfaf7abc2a4a4aa2280d6d8a0a 100644 (file)
@@ -2439,6 +2439,11 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) {
   return Success;
 }
 
+void ASTReader::makeNamesVisible(const HiddenNames &Names) {
+  for (unsigned I = 0, N = Names.size(); I != N; ++I)
+    Names[I]->ModulePrivate = false;    
+}
+
 void ASTReader::makeModuleVisible(Module *Mod, 
                                   Module::NameVisibilityKind NameVisibility) {
   llvm::SmallPtrSet<Module *, 4> Visited;
@@ -2457,8 +2462,13 @@ void ASTReader::makeModuleVisible(Module *Mod,
     // Update the module's name visibility.
     Mod->NameVisibility = NameVisibility;
     
-    // FIXME: If we've already deserialized any names from this module,
+    // If we've already deserialized any names from this module,
     // mark them as visible.
+    HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
+    if (Hidden != HiddenNamesMap.end()) {
+      makeNamesVisible(Hidden->second);
+      HiddenNamesMap.erase(Hidden);
+    }
     
     // Push any non-explicit submodules onto the stack to be marked as
     // visible.
@@ -2776,6 +2786,15 @@ void ASTReader::InitializeContext() {
   }
 }
 
+void ASTReader::finalizeForWriting() {
+  for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
+                                 HiddenEnd = HiddenNamesMap.end();
+       Hidden != HiddenEnd; ++Hidden) {
+    makeNamesVisible(Hidden->second);
+  }
+  HiddenNamesMap.clear();
+}
+
 /// \brief Retrieve the name of the original source file name
 /// directly from the AST file, without actually loading the AST
 /// file.
index 397671f85e8e0393470fa8a04f74d9a1a2395aeb..85cd72840af1e0ed6bda11b6325dc9fb0a24e836 100644 (file)
@@ -86,6 +86,14 @@ namespace clang {
       Reader.ReadDeclarationNameInfo(F, NameInfo, R, I);
     }
 
+    serialization::SubmoduleID readSubmoduleID(const RecordData &R, 
+                                               unsigned &I) {
+      if (I >= R.size())
+        return 0;
+      
+      return Reader.getGlobalSubmoduleID(F, R[I++]);
+    }
+    
     void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
                                const RecordData &R, unsigned &I);
 
@@ -253,10 +261,25 @@ void ASTDeclReader::VisitDecl(Decl *D) {
   D->setAccess((AccessSpecifier)Record[Idx++]);
   D->FromASTFile = true;
   D->ModulePrivate = Record[Idx++];
-  
-  unsigned SubmoduleID = Record[Idx++];
-  // FIXME: Actual use the submodule ID to determine visibility.
-  (void)SubmoduleID;
+
+  // Determine whether this declaration is part of a (sub)module. If so, it
+  // may not yet be visible.
+  if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
+    // Module-private declarations are never visible, so there is no work to do.
+    if (!D->ModulePrivate) {
+      if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
+        if (Owner->NameVisibility != Module::AllVisible) {
+          // The owning module is not visible. Mark this declaration as
+          // module-private, 
+          D->ModulePrivate = true;
+          
+          // Note that this declaration was hidden because its owning module is 
+          // not yet visible.
+          Reader.HiddenNamesMap[Owner].push_back(D);
+        }
+      }
+    }
+  }
 }
 
 void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
index e37aa7320fe3b957e3b686d91c7e609b0ebe9d52..1b554ef3c45363f5ccc5ce9953873f5aa75a0bb1 100644 (file)
@@ -2958,6 +2958,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                              Module *WritingModule) {
   using namespace llvm;
 
+  // Make sure that the AST reader knows to finalize itself.
+  if (Chain)
+    Chain->finalizeForWriting();
+  
   ASTContext &Context = SemaRef.Context;
   Preprocessor &PP = SemaRef.PP;
 
diff --git a/test/Modules/Inputs/submodules/hash_map.h b/test/Modules/Inputs/submodules/hash_map.h
new file mode 100644 (file)
index 0000000..56f0749
--- /dev/null
@@ -0,0 +1 @@
+template<typename Key, typename Data> class hash_map { };
index 6d19975c9645b2df77b392705e5d9232faed9ac6..16cedac231e750ef852b31b27309bde7ff11000e 100644 (file)
@@ -1,4 +1,5 @@
 module std {
   module vector { header "vector.h" }
   module type_traits { header "type_traits.h" }
+  explicit module hash_map { header "hash_map.h" }
 }
index 3123dd1c84b463747862222f8ecb1571c1c35a2f..2dcf3e57317ecbb0ae453c76cd1268522121aa3d 100644 (file)
@@ -1 +1 @@
-template<typename T> class vector;
+template<typename T> class vector { };
index a161f33efa94fc66672fcd1522669547ba987298..1b5ef9959015ba98395049a7d68515351dd65a61 100644 (file)
@@ -11,3 +11,4 @@
 #ifdef DEPENDS_ON_MODULE
 #  error DEPENDS_ON_MODULE should have been hidden
 #endif
+
index 59181c533d48f7c4431af6f7a81f17af4d8a5180..93722e9fe2a7d239b833c72be9e5593382ac87bb 100644 (file)
@@ -5,6 +5,12 @@
 
 __import_module__ diamond_bottom;
 
+// FIXME: We want 'bottom' to re-export left and right, and both of those to
+// re-export 'top'.
+__import_module__ diamond_top;
+__import_module__ diamond_left;
+__import_module__ diamond_right;
+
 void test_diamond(int i, float f, double d, char c) {
   top(&i);
   left(&f);
diff --git a/test/Modules/submodules-preprocess.cpp b/test/Modules/submodules-preprocess.cpp
new file mode 100644 (file)
index 0000000..1f0f377
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Eonly -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/submodules %s -verify
+
+__import_module__ std.vector;
+
+vector<int> vi;
+remove_reference<int&>::type *int_ptr = 0;
+
+__import_module__ std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
+
+vector<float> vf;
+remove_reference<int&>::type *int_ptr2 = 0;
+
+__import_module__ std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
index fd1426d012f9c0a2636d6908a0e37f07da9cf17a..ce7054f30755009f9c453136a4d71bd9f23daf62 100644 (file)
@@ -1,7 +1,28 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -Eonly -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/submodules %s -verify
 // RUN: %clang_cc1 -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/submodules %s -verify
 
 __import_module__ std.vector;
+
+vector<int> vi;
+
+// Note: remove_reference is not visible yet.
+remove_reference<int&>::type *int_ptr = 0; // expected-error{{unknown type name 'remove_reference'}} \
+// expected-error{{expected unqualified-id}}
+
 __import_module__ std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
+
+vector<float> vf;
+remove_reference<int&>::type *int_ptr2 = 0;
+
 __import_module__ std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
+
+__import_module__ std; // import everything in 'std'
+
+// hash_map still isn't available.
+hash_map<int, float> ints_to_floats; // expected-error{{unknown type name 'hash_map'}} \
+// expected-error{{expected unqualified-id}}
+
+__import_module__ std.hash_map;
+
+hash_map<int, float> ints_to_floats2;
+