[cfe-commits] r145665 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td include/clang/Basic/Module.h include/clang/Lex/ModuleMap.h include/clang/Lex/Preprocessor.h lib/Lex/ModuleMap.cpp lib/Lex/Preprocessor.cpp lib/Sema/Sema.cpp test/Modules/Inputs/module.map

Douglas Gregor dgregor at apple.com
Thu Dec 1 17:47:07 PST 2011


Author: dgregor
Date: Thu Dec  1 19:47:07 2011
New Revision: 145665

URL: http://llvm.org/viewvc/llvm-project?rev=145665&view=rev
Log:
Implementing parsing and resolution of module export declarations
within module maps, which will (eventually) be used to re-export a
module from another module. There are still some pieces missing,
however.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Basic/Module.h
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/test/Modules/Inputs/module.map

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Dec  1 19:47:07 2011
@@ -399,6 +399,12 @@
   "submodule '%0' can not have an umbrella header">;
 def err_mmap_umbrella_clash : Error<
   "umbrella header for module '%0' already covers this directory">;
+def err_mmap_export_module_id : Error<
+  "expected an exported module name or '*'">;
+def err_mmap_missing_module_unqualified : Error<
+  "no module named '%0' visible from '%1'">;
+def err_mmap_missing_module_qualified : Error<
+  "no module named '%0' in '%1'">;
 
 def warn_auto_module_import : Warning<
   "treating #%select{include|import|include_next|__include_macros}0 as an "

Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Thu Dec  1 19:47:07 2011
@@ -15,10 +15,12 @@
 #define LLVM_CLANG_BASIC_MODULE_H
 
 #include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include <string>
+#include <utility>
 
 namespace llvm {
   class raw_ostream;
@@ -28,6 +30,10 @@
   
 class FileEntry;
 
+/// \brief Describes the name of a module.
+typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
+  ModuleId;
+  
 /// \brief Describes a module or submodule.
 class Module {
 public:
@@ -73,6 +79,33 @@
   ///\ brief The visibility of names within this particular module.
   NameVisibilityKind NameVisibility;
   
+  /// \brief Describes an exported module.
+  ///
+  /// The pointer is the module being re-exported, while the bit will be true
+  /// to indicate that this is a wildcard export.
+  typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl;
+  
+  /// \brief The set of export declarations.
+  llvm::SmallVector<ExportDecl, 2> Exports;
+  
+  /// \brief Describes an exported module that has not yet been resolved
+  /// (perhaps because the module it refers to has not yet been loaded).
+  struct UnresolvedExportDecl {
+    /// \brief The location of the 'export' keyword in the module map file.
+    SourceLocation ExportLoc;
+    
+    /// \brief The name of the module.
+    ModuleId Id;
+    
+    /// \brief Whether this export declaration ends in a wildcard, indicating
+    /// that all of its submodules should be exported (rather than the named
+    /// module itself).
+    bool Wildcard;
+  };
+  
+  /// \brief The set of export declarations that have yet to be resolved.
+  llvm::SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
+  
   /// \brief Construct a top-level module.
   explicit Module(StringRef Name, SourceLocation DefinitionLoc,
                   bool IsFramework)

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Dec  1 19:47:07 2011
@@ -57,6 +57,22 @@
   
   friend class ModuleMapParser;
   
+  /// \brief Resolve the given export declaration into an actual export
+  /// declaration.
+  ///
+  /// \param Mod The module in which we're resolving the export declaration.
+  ///
+  /// \param Unresolved The export declaration to resolve.
+  ///
+  /// \param Complain Whether this routine should complain about unresolvable
+  /// exports.
+  ///
+  /// \returns The resolved export declaration, which will have a NULL pointer
+  /// if the export could not be resolved.
+  Module::ExportDecl 
+  resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved,
+                bool Complain);
+  
 public:
   /// \brief Construct a new module map.
   ///
@@ -86,6 +102,28 @@
   ///
   /// \returns The named module, if known; otherwise, returns null.
   Module *findModule(StringRef Name);
+
+  /// \brief Retrieve a module with the given name using lexical name lookup,
+  /// starting at the given context.
+  ///
+  /// \param The name of the module to look up.
+  ///
+  /// \param Context The module context, from which we will perform lexical
+  /// name lookup.
+  ///
+  /// \returns The named module, if known; otherwise, returns null.
+  Module *lookupModuleUnqualified(StringRef Name, Module *Context);
+
+  /// \brief Retrieve a module with the given name within the given context,
+  /// using direct (qualified) name lookup.
+  ///
+  /// \param The name of the module to look up.
+  /// 
+  /// \param Context The module for which we will look for a submodule. If
+  /// null, we will look for a top-level module.
+  ///
+  /// \returns The named submodule, if known; otherwose, returns null.
+  Module *lookupModuleQualified(StringRef Name, Module *Context);
   
   /// \brief Find a new module or submodule, or create it if it does not already
   /// exist.
@@ -118,7 +156,17 @@
   /// \returns The file entry for the module map file containing the given
   /// module, or NULL if the module definition was inferred.
   const FileEntry *getContainingModuleMapFile(Module *Module);
-  
+
+  /// \brief Resolve all of the unresolved exports in the given module.
+  ///
+  /// \param Mod The module whose exports should be resolved.
+  ///
+  /// \param Complain Whether to emit diagnostics for failures.
+  ///
+  /// \returns true if any errors were encountered while resolving exports,
+  /// false otherwise.
+  bool resolveExports(Module *Mod, bool Complain);
+
   /// \brief Parse the given module map file, and record any modules we 
   /// encounter.
   ///

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Thu Dec  1 19:47:07 2011
@@ -993,6 +993,9 @@
   unsigned getCounterValue() const { return CounterValue; }
   void setCounterValue(unsigned V) { CounterValue = V; }
 
+  /// \brief Retrieves the module that we're currently building, if any.
+  Module *getCurrentModule();
+  
   /// AllocateMacroInfo - Allocate a new MacroInfo object with the provide
   ///  SourceLocation.
   MacroInfo *AllocateMacroInfo(SourceLocation L);

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Dec  1 19:47:07 2011
@@ -27,6 +27,41 @@
 #include "llvm/ADT/StringSwitch.h"
 using namespace clang;
 
+Module::ExportDecl 
+ModuleMap::resolveExport(Module *Mod, 
+                         const Module::UnresolvedExportDecl &Unresolved,
+                         bool Complain) {
+  // Find the starting module.
+  Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
+  if (!Context) {
+    if (Complain)
+      Diags->Report(Unresolved.Id[0].second, 
+                    diag::err_mmap_missing_module_unqualified)
+        << Unresolved.Id[0].first << Mod->getFullModuleName();
+    
+    return Module::ExportDecl();
+  }
+
+  // Dig into the module path.
+  for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
+    Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
+                                        Context);
+    if (!Sub) {
+      if (Complain)
+        Diags->Report(Unresolved.Id[I].second, 
+                      diag::err_mmap_missing_module_qualified)
+          << Unresolved.Id[I].first << Context->getFullModuleName()
+          << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second);
+      
+      return Module::ExportDecl();      
+    }
+    
+    Context = Sub;
+  }
+  
+  return Module::ExportDecl(Context, Unresolved.Wildcard);
+}
+
 ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) {
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
   Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
@@ -97,6 +132,26 @@
   return 0;
 }
 
+Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
+  for(; Context; Context = Context->Parent) {
+    if (Module *Sub = lookupModuleQualified(Name, Context))
+      return Sub;
+  }
+  
+  return findModule(Name);
+}
+
+Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) {
+  if (!Context)
+    return findModule(Name);
+  
+  llvm::StringMap<Module *>::iterator Sub = Context->SubModules.find(Name);
+  if (Sub != Context->SubModules.end())
+    return Sub->getValue();
+
+  return 0;
+}
+
 std::pair<Module *, bool> 
 ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
                               bool IsExplicit) {
@@ -169,6 +224,20 @@
   }
 }
 
+bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
+  bool HadError = false;
+  for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) {
+    Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I], 
+                                              Complain);
+    if (Export.getPointer())
+      Mod->Exports.push_back(Export);
+    else
+      HadError = true;
+  }
+  Mod->UnresolvedExports.clear();
+  return HadError;
+}
+
 //----------------------------------------------------------------------------//
 // Module map file parser
 //----------------------------------------------------------------------------//
@@ -181,9 +250,12 @@
       HeaderKeyword,
       Identifier,
       ExplicitKeyword,
+      ExportKeyword,
       FrameworkKeyword,
       ModuleKeyword,
+      Period,
       UmbrellaKeyword,
+      Star,
       StringLiteral,
       LBrace,
       RBrace
@@ -247,6 +319,7 @@
     void parseModuleDecl();
     void parseUmbrellaDecl();
     void parseHeaderDecl();
+    void parseExportDecl();
     
   public:
     explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, 
@@ -283,6 +356,7 @@
     Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
                  .Case("header", MMToken::HeaderKeyword)
                  .Case("explicit", MMToken::ExplicitKeyword)
+                 .Case("export", MMToken::ExportKeyword)
                  .Case("framework", MMToken::FrameworkKeyword)
                  .Case("module", MMToken::ModuleKeyword)
                  .Case("umbrella", MMToken::UmbrellaKeyword)
@@ -297,10 +371,18 @@
     Tok.Kind = MMToken::LBrace;
     break;
 
+  case tok::period:
+    Tok.Kind = MMToken::Period;
+    break;
+      
   case tok::r_brace:
     Tok.Kind = MMToken::RBrace;
     break;
       
+  case tok::star:
+    Tok.Kind = MMToken::Star;
+    break;
+      
   case tok::string_literal: {
     // Parse the string literal.
     LangOptions LangOpts;
@@ -373,6 +455,7 @@
 ///     umbrella-declaration
 ///     header-declaration
 ///     'explicit'[opt] module-declaration
+///     export-declaration
 void ModuleMapParser::parseModuleDecl() {
   assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
          Tok.is(MMToken::FrameworkKeyword));
@@ -457,6 +540,10 @@
       parseModuleDecl();
       break;
         
+    case MMToken::ExportKeyword:
+      parseExportDecl();
+      break;
+        
     case MMToken::HeaderKeyword:
       parseHeaderDecl();
       break;
@@ -464,7 +551,7 @@
     case MMToken::UmbrellaKeyword:
       parseUmbrellaDecl();
       break;
-        
+
     default:
       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
       consumeToken();
@@ -625,6 +712,52 @@
   }
 }
 
+/// \brief Parse a module export declaration.
+///
+///   export-declaration:
+///     'export' wildcard-module-id
+///
+///   wildcard-module-id:
+///     identifier
+///     '*'
+///     identifier '.' wildcard-module-id
+void ModuleMapParser::parseExportDecl() {
+  assert(Tok.is(MMToken::ExportKeyword));
+  SourceLocation ExportLoc = consumeToken();
+  
+  // Parse the module-id with an optional wildcard at the end.
+  ModuleId ParsedModuleId;
+  bool Wildcard = false;
+  do {
+    if (Tok.is(MMToken::Identifier)) {
+      ParsedModuleId.push_back(std::make_pair(Tok.getString(), 
+                                              Tok.getLocation()));
+      consumeToken();
+      
+      if (Tok.is(MMToken::Period)) {
+        consumeToken();
+        continue;
+      } 
+      
+      break;
+    }
+    
+    if(Tok.is(MMToken::Star)) {
+      Wildcard = true;
+      break;
+    }
+    
+    Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+    HadError = true;
+    return;
+  } while (true);
+  
+  Module::UnresolvedExportDecl Unresolved = { 
+    ExportLoc, ParsedModuleId, Wildcard 
+  };
+  ActiveModule->UnresolvedExports.push_back(Unresolved);
+}
+
 /// \brief Parse a module map file.
 ///
 ///   module-map-file:
@@ -641,10 +774,13 @@
       break;
       
     case MMToken::ExplicitKeyword:
+    case MMToken::ExportKeyword:
     case MMToken::HeaderKeyword:
     case MMToken::Identifier:
     case MMToken::LBrace:
+    case MMToken::Period:
     case MMToken::RBrace:
+    case MMToken::Star:
     case MMToken::StringLiteral:
     case MMToken::UmbrellaKeyword:
       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Thu Dec  1 19:47:07 2011
@@ -369,7 +369,12 @@
     Tok.setLiteralData(DestPtr);
 }
 
-
+Module *Preprocessor::getCurrentModule() {
+  if (getLangOptions().CurrentModule.empty())
+    return 0;
+  
+  return getHeaderSearchInfo().getModule(getLangOptions().CurrentModule);
+}
 
 //===----------------------------------------------------------------------===//
 // Preprocessor Initialization Methods

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Thu Dec  1 19:47:07 2011
@@ -33,11 +33,11 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
-
 using namespace clang;
 using namespace sema;
 
@@ -484,6 +484,32 @@
   }
 
   if (TUKind == TU_Module) {
+    // If we are building a module, resolve all of the exported declarations
+    // now.
+    if (Module *CurrentModule = PP.getCurrentModule()) {
+      ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+      
+      llvm::SmallVector<Module *, 2> Stack;
+      Stack.push_back(CurrentModule);
+      while (!Stack.empty()) {
+        Module *Mod = Stack.back();
+        Stack.pop_back();
+        
+        // Resolve the exported declarations.
+        // FIXME: Actually complain, once we figure out how to teach the
+        // diagnostic client to deal with complains in the module map at this
+        // point.
+        ModMap.resolveExports(Mod, /*Complain=*/false);
+        
+        // Queue the submodules, so their exports will also be resolved.
+        for (llvm::StringMap<Module *>::iterator Sub = Mod->SubModules.begin(),
+             SubEnd = Mod->SubModules.end();
+             Sub != SubEnd; ++Sub) {
+          Stack.push_back(Sub->getValue());
+        }
+      }
+    }
+    
     // Modules don't need any of the checking below.
     TUScope = 0;
     return;

Modified: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/module.map Thu Dec  1 19:47:07 2011
@@ -1,7 +1,17 @@
 module diamond_top { header "diamond_top.h" }
-module diamond_left { header "diamond_left.h" }
-module diamond_right { header "diamond_right.h" }
-module diamond_bottom { header "diamond_bottom.h" }
+module diamond_left { 
+  header "diamond_left.h" 
+  export diamond_top
+}
+module diamond_right { 
+  header "diamond_right.h" 
+  export diamond_top
+}
+module diamond_bottom { 
+  header "diamond_bottom.h" 
+  export diamond_left
+  export diamond_right
+}
 module irgen { header "irgen.h" }
 module lookup_left_objc { header "lookup_left.h" }
 module lookup_right_objc { header "lookup_right.h" }





More information about the cfe-commits mailing list