]> granicus.if.org Git - clang/commitdiff
Introduce the notion of name visibility into modules. For a given
authorDouglas Gregor <dgregor@apple.com>
Thu, 1 Dec 2011 17:11:21 +0000 (17:11 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 1 Dec 2011 17:11:21 +0000 (17:11 +0000)
(sub)module, all of the names may be hidden, just the macro names may
be exposed (for example, after the preprocessor has seen the import of
the module but the parser has not), or all of the names may be
exposed. Importing a module makes its names, and the names in any of
its non-explicit submodules, visible to name lookup (transitively).

This commit only introduces the notion of name visible and marks
modules and submodules as visible when they are imported. The actual
name-hiding logic in the AST reader will follow (along with test cases).

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

include/clang/Basic/Module.h
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
include/clang/Lex/ModuleLoader.h
include/clang/Serialization/ASTReader.h
lib/Frontend/CompilerInstance.cpp
lib/Lex/PPDirectives.cpp
lib/Lex/Preprocessor.cpp
lib/Sema/SemaDecl.cpp
lib/Serialization/ASTReader.cpp

index 4f5280738fa82b1e52e8de7504578721b093bc04..4eaa1be291573ff7993a5992d47c9a6ebef3b3b7 100644 (file)
@@ -58,17 +58,33 @@ public:
   /// \brief Whether this is an explicit submodule.
   bool IsExplicit;
   
+  /// \brief Describes the visibility of the various names within a
+  /// particular module.
+  enum NameVisibilityKind {
+    /// \brief All of the names in this module are hidden.
+    ///
+    Hidden,
+    /// \brief Only the macro names in this module are visible.
+    MacrosVisible,
+    /// \brief All of the names in this module are visible.
+    AllVisible
+  };  
+  
+  ///\ brief The visibility of names within this particular module.
+  NameVisibilityKind NameVisibility;
+  
   /// \brief Construct a top-level module.
   explicit Module(StringRef Name, SourceLocation DefinitionLoc,
                   bool IsFramework)
     : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), UmbrellaHeader(0),
-      IsFramework(IsFramework), IsExplicit(false) { }
+      IsFramework(IsFramework), IsExplicit(false), NameVisibility(Hidden) { }
   
   /// \brief Construct  a new module or submodule.
   Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, 
          bool IsFramework, bool IsExplicit)
     : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), 
-      UmbrellaHeader(0), IsFramework(IsFramework), IsExplicit(IsExplicit) { }
+      UmbrellaHeader(0), IsFramework(IsFramework), IsExplicit(IsExplicit), 
+      NameVisibility(Hidden) { }
   
   ~Module();
   
index 4cab303ba4d151dd559c49f4330a335fd24390f7..d65da5d67bd98b7f0a95fcc6c3ab6d75cc5e4feb 100644 (file)
@@ -781,7 +781,8 @@ public:
   /// \returns True if an error occurred, false otherwise.
   bool serialize(raw_ostream &OS);
   
-  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path) {
+  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+                             Module::NameVisibilityKind Visibility) {
     // ASTUnit doesn't know how to load modules (not that this matters).
     return 0;
   }
index 9cd09ee10c099505216fa4058d0aa2ae2bc0e3f0..21f8eeead3d6b74903df290ce6dc645b3fb236f3 100644 (file)
@@ -641,7 +641,8 @@ public:
 
   /// }
   
-  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path);
+  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+                             Module::NameVisibilityKind Visibility);
 };
 
 } // end namespace clang
index 6a7fe0204f3d6d930d5b554ad926fa56aa2fd7bd..0bd97b6bd4b9e362e7445ac06f7527b03ba1b65c 100644 (file)
 #ifndef LLVM_CLANG_LEX_MODULE_LOADER_H
 #define LLVM_CLANG_LEX_MODULE_LOADER_H
 
+#include "clang/Basic/Module.h"
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/ArrayRef.h"
 
 namespace clang {
 
 class IdentifierInfo;
-class Module;
   
 /// \brief A sequence of identifier/location pairs used to describe a particular
 /// module or submodule, e.g., std.vector.
@@ -41,12 +41,17 @@ public:
   /// parameters.
   ///
   /// \param ImportLoc The location of the 'import' keyword.
+  ///
   /// \param Path The identifiers (and their locations) of the module
   /// "path", e.g., "std.vector" would be split into "std" and "vector".
+  /// 
+  /// \param Visibility The visibility provided for the names in the loaded
+  /// module.
   ///
   /// \returns If successful, returns the loaded module. Otherwise, returns 
   /// NULL to indicate that the module could not be loaded.
-  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path) = 0;
+  virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+                             Module::NameVisibilityKind Visibility) = 0;
 };
   
 }
index 0e659acfa0f7e0c20f1193c08b3f0ab355f9b71c..3f66eb51183db2c7839e9fe344bd0628a35f3f14 100644 (file)
@@ -803,6 +803,16 @@ public:
   /// the actual file in the file system.
   ASTReadResult validateFileEntries(ModuleFile &M);
 
+  /// \brief Make the entities in the given module and any of its (non-explicit)
+  /// submodules visible to name lookup.
+  ///
+  /// \param Mod The module whose names should be made visible.
+  ///
+  /// \param Visibility The level of visibility to give the names in the module.
+  /// Visibility can only be increased over time.
+  void makeModuleVisible(Module *Mod, 
+                         Module::NameVisibilityKind NameVisibility);
+  
   /// \brief Set the AST callbacks listener.
   void setListener(ASTReaderListener *listener) {
     Listener.reset(listener);
index 743a447c323703e28f9646e1aa97fe650a6acdcb..746c00a3619ee4795a93aee2a79365215a4a7f23 100644 (file)
@@ -1069,12 +1069,17 @@ static void compileModule(CompilerInstance &ImportingInstance,
 }
 
 Module *CompilerInstance::loadModule(SourceLocation ImportLoc, 
-                                     ModuleIdPath Path) {
+                                     ModuleIdPath Path,
+                                     Module::NameVisibilityKind Visibility) {
   // If we've already handled this import, just return the cached result.
   // This one-element cache is important to eliminate redundant diagnostics
   // when both the preprocessor and parser see the same import declaration.
-  if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc)
+  if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
+    // Make the named module visible.
+    if (LastModuleImportResult)
+      ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility);
     return LastModuleImportResult;
+  }
   
   // Determine what file we're searching from.
   SourceManager &SourceMgr = getSourceManager();
@@ -1253,7 +1258,9 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
     }
   }
   
-  // FIXME: Tell the AST reader to make the named submodule visible.
+  // Make the named module visible.
+  if (Module)
+    ModuleManager->makeModuleVisible(Module, Visibility);
   
   LastModuleImportLoc = ImportLoc;
   LastModuleImportResult = Module;
index 81cb52620983ea93f806248c6888bfe960c4d615..836d21b20475595e6afe276cc93d651297ca41d1 100644 (file)
@@ -1360,8 +1360,10 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
            "__import_module__ " + PathString.str().str() + ";");
     
     // Load the module.
-    // FIXME: Deal with __include_macros here.
-    TheModuleLoader.loadModule(IncludeTok.getLocation(), Path);
+    // If this was an #__include_macros directive, only make macros visible.
+    Module::NameVisibilityKind Visibility 
+      = (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
+    TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility);
     return;
   }
   
index b01113041eb26ebe19128c182105985885155488..180e1e2c258d532ab6d4415f992e6e4397931867 100644 (file)
@@ -593,7 +593,8 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
 
   // If we have a non-empty module path, load the named module.
   if (!ModuleImportPath.empty())
-    (void)TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath);
+    (void)TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath,
+                                     Module::MacrosVisible);
 }
 
 void Preprocessor::AddCommentHandler(CommentHandler *Handler) {
index 48f4c4f0cba3b7b9dc8d783a77806cb21899f188..1e57a00f1f178e7692f537be7d1e293f469aafb2 100644 (file)
@@ -9892,7 +9892,8 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
 }
 
 DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc, ModuleIdPath Path) {
-  Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path);
+  Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path, 
+                                                Module::AllVisible);
   if (!Mod)
     return true;
   
index d43f8c1f45d00634de20c6d38b1dcd12802f2857..258baebc05cfbf8bc0ed10135aff12b119cf6775 100644 (file)
@@ -2439,6 +2439,38 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) {
   return Success;
 }
 
+void ASTReader::makeModuleVisible(Module *Mod, 
+                                  Module::NameVisibilityKind NameVisibility) {
+  llvm::SmallPtrSet<Module *, 4> Visited;
+  llvm::SmallVector<Module *, 4> Stack;
+  Stack.push_back(Mod);  
+  while (!Stack.empty()) {
+    Mod = Stack.back();
+    Stack.pop_back();
+
+    if (NameVisibility <= Mod->NameVisibility) {
+      // This module already has this level of visibility (or greater), so 
+      // there is nothing more to do.
+      continue;
+    }
+    
+    // Update the module's name visibility.
+    Mod->NameVisibility = NameVisibility;
+    
+    // FIXME: If we've already deserialized any names from this module,
+    // mark them as visible.
+    
+    // Push any non-explicit submodules onto the stack to be marked as
+    // visible.
+    for (llvm::StringMap<Module *>::iterator Sub = Mod->SubModules.begin(),
+                                          SubEnd = Mod->SubModules.end();
+         Sub != SubEnd; ++Sub) {
+      if (!Sub->getValue()->IsExplicit && Visited.insert(Sub->getValue()))
+        Stack.push_back(Sub->getValue());
+    }
+  }
+}
+
 ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
                                             ModuleKind Type) {
   switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {