[cfe-commits] r146012 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td lib/Lex/HeaderSearch.cpp lib/Lex/ModuleMap.cpp test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/ test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h test/Modules/Inputs/DependsOnModule.framework/module_private.map test/Modules/auto-module-import.m

Douglas Gregor dgregor at apple.com
Tue Dec 6 18:23:45 PST 2011


Author: dgregor
Date: Tue Dec  6 20:23:45 2011
New Revision: 146012

URL: http://llvm.org/viewvc/llvm-project?rev=146012&view=rev
Log:
Implement basic support for private headers in frameworks. In essence,
when we load a module map (module.map) from a directory, also load a
private module map (module_private.map) for that directory, if
present. That private module map can inject a new submodule that
captures private headers.

Added:
    cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/
    cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h
    cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/test/Modules/auto-module-import.m

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Tue Dec  6 20:23:45 2011
@@ -413,7 +413,11 @@
   "expected module export wildcard">;
 def err_mmap_expected_export_wildcard : Error<
   "only '*' can be exported from an inferred submodule">;
-
+def err_mmap_explicit_top_level : Error<
+  "'explicit' is not permitted on top-level modules">;
+def err_mmap_nested_submodule_id : Error<
+  "qualified module name can only be used to define modules at the top level">;
+  
 def warn_auto_module_import : Warning<
   "treating #%select{include|import|include_next|__include_macros}0 as an "
   "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Tue Dec  6 20:23:45 2011
@@ -870,15 +870,33 @@
   
   llvm::SmallString<128> ModuleMapFileName;
   ModuleMapFileName += Dir->getName();
+  unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
   llvm::sys::path::append(ModuleMapFileName, "module.map");
   if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
     // We have found a module map file. Try to parse it.
-    if (!ModMap.parseModuleMapFile(ModuleMapFile)) {
-      // This directory has a module map.
-      DirectoryHasModuleMap[Dir] = true;
-      
-      return LMM_NewlyLoaded;
+    if (ModMap.parseModuleMapFile(ModuleMapFile)) {
+      // No suitable module map.
+      DirectoryHasModuleMap[Dir] = false;
+      return LMM_InvalidModuleMap;
     }
+
+    // This directory has a module map.
+    DirectoryHasModuleMap[Dir] = true;
+    
+    // Check whether there is a private module map that we need to load as well.
+    ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
+                            ModuleMapFileName.end());
+    llvm::sys::path::append(ModuleMapFileName, "module_private.map");
+    if (const FileEntry *PrivateModuleMapFile
+                                        = FileMgr.getFile(ModuleMapFileName)) {
+      if (ModMap.parseModuleMapFile(PrivateModuleMapFile)) {
+        // No suitable module map.
+        DirectoryHasModuleMap[Dir] = false;
+        return LMM_InvalidModuleMap;
+      }      
+    }
+    
+    return LMM_NewlyLoaded;
   }
   
   // No suitable module map.

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Tue Dec  6 20:23:45 2011
@@ -435,7 +435,10 @@
     /// \brief Skip tokens until we reach the a token with the given kind
     /// (or the end of the file).
     void skipUntil(MMToken::TokenKind K);
-    
+
+    typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
+      ModuleId;
+    bool parseModuleId(ModuleId &Id);
     void parseModuleDecl();
     void parseUmbrellaDecl();
     void parseHeaderDecl();
@@ -567,15 +570,42 @@
   } while (true);
 }
 
+/// \brief Parse a module-id.
+///
+///   module-id:
+///     identifier
+///     identifier '.' module-id
+///
+/// \returns true if an error occurred, false otherwise.
+bool ModuleMapParser::parseModuleId(ModuleId &Id) {
+  Id.clear();
+  do {
+    if (Tok.is(MMToken::Identifier)) {
+      Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation()));
+      consumeToken();
+    } else {
+      Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
+      return true;
+    }
+    
+    if (!Tok.is(MMToken::Period))
+      break;
+    
+    consumeToken();
+  } while (true);
+  
+  return false;
+}
+
 /// \brief Parse a module declaration.
 ///
 ///   module-declaration:
-///     'framework'[opt] 'module' identifier { module-member* }
+///     'explicit'[opt] 'framework'[opt] 'module' module-id { module-member* }
 ///
 ///   module-member:
 ///     umbrella-declaration
 ///     header-declaration
-///     'explicit'[opt] submodule-declaration
+///     submodule-declaration
 ///     export-declaration
 ///
 ///   submodule-declaration:
@@ -584,14 +614,14 @@
 void ModuleMapParser::parseModuleDecl() {
   assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
          Tok.is(MMToken::FrameworkKeyword));
-
   // Parse 'explicit' or 'framework' keyword, if present.
+  SourceLocation ExplicitLoc;
   bool Explicit = false;
   bool Framework = false;
 
   // Parse 'explicit' keyword, if present.
   if (Tok.is(MMToken::ExplicitKeyword)) {
-    consumeToken();
+    ExplicitLoc = consumeToken();
     Explicit = true;
   }
 
@@ -616,13 +646,52 @@
     return parseInferredSubmoduleDecl(Explicit);
   
   // Parse the module name.
-  if (!Tok.is(MMToken::Identifier)) {
-    Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
+  ModuleId Id;
+  if (parseModuleId(Id)) {
+    HadError = true;
+    return;
+  }
+  
+  if (ActiveModule) {
+    if (Id.size() > 1) {
+      Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
+        << SourceRange(Id.front().second, Id.back().second);
+      
+      HadError = true;
+      return;
+    }
+  } else if (Id.size() == 1 && Explicit) {
+    // Top-level modules can't be explicit.
+    Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
+    Explicit = false;
+    ExplicitLoc = SourceLocation();
     HadError = true;
-    return;    
   }
-  StringRef ModuleName = Tok.getString();
-  SourceLocation ModuleNameLoc = consumeToken();
+  
+  Module *PreviousActiveModule = ActiveModule;  
+  if (Id.size() > 1) {
+    // This module map defines a submodule. Go find the module of which it
+    // is a submodule.
+    ActiveModule = 0;
+    for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {
+      if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {
+        ActiveModule = Next;
+        continue;
+      }
+      
+      if (ActiveModule) {
+        Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
+          << Id[I].first << ActiveModule->getTopLevelModule();
+      } else {
+        Diags.Report(Id[I].second, diag::err_mmap_expected_module_name);
+      }
+      HadError = true;
+      return;
+    }
+  } 
+  
+  StringRef ModuleName = Id.back().first;
+  SourceLocation ModuleNameLoc = Id.back().second;
   
   // Parse the opening brace.
   if (!Tok.is(MMToken::LBrace)) {
@@ -699,8 +768,8 @@
     HadError = true;
   }
 
-  // We're done parsing this module. Pop back to our parent scope.
-  ActiveModule = ActiveModule->Parent;
+  // We're done parsing this module. Pop back to the previous module.
+  ActiveModule = PreviousActiveModule;
 }
 
 /// \brief Append to \p Paths the set of paths needed to get to the 
@@ -738,7 +807,7 @@
     HadError = true;
     return;
   }
-  StringRef FileName = Tok.getString();
+  std::string FileName = Tok.getString();
   SourceLocation FileNameLoc = consumeToken();
 
   // Check whether we already have an umbrella header.
@@ -829,26 +898,45 @@
     HadError = true;
     return;
   }
-  StringRef FileName = Tok.getString();
+  std::string FileName = Tok.getString();
   SourceLocation FileNameLoc = consumeToken();
   
   // Look for this file.
+  const FileEntry *File = 0;
   llvm::SmallString<128> PathName;
-  if (llvm::sys::path::is_relative(FileName)) {
-    // FIXME: Change this search to also look for private headers!
+  if (llvm::sys::path::is_absolute(FileName)) {
+    PathName = FileName;
+    File = SourceMgr.getFileManager().getFile(PathName);
+  } else {
+    // Search for the header file within the search directory.
     PathName += Directory->getName();
+    unsigned PathLength = PathName.size();
     
     if (ActiveModule->isPartOfFramework()) {
       appendSubframeworkPaths(ActiveModule, PathName);
+      
+      // Check whether this file is in the public headers.
       llvm::sys::path::append(PathName, "Headers");
+      llvm::sys::path::append(PathName, FileName);
+      File = SourceMgr.getFileManager().getFile(PathName);
+      
+      if (!File) {
+        // Check whether this file is in the private headers.
+        PathName.resize(PathLength);
+        llvm::sys::path::append(PathName, "PrivateHeaders");
+        llvm::sys::path::append(PathName, FileName);
+        File = SourceMgr.getFileManager().getFile(PathName);
+      }
+    } else {
+      // Lookup for normal headers.
+      llvm::sys::path::append(PathName, FileName);
+      File = SourceMgr.getFileManager().getFile(PathName);
     }
   }
   
-  llvm::sys::path::append(PathName, FileName);
-  
   // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
   // Come up with a lazy way to do this.
-  if (const FileEntry *File = SourceMgr.getFileManager().getFile(PathName)) {
+  if (File) {
     if (const Module *OwningModule = Map.Headers[File]) {
       Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
         << FileName << OwningModule->getFullModuleName();
@@ -1012,12 +1100,12 @@
     case MMToken::EndOfFile:
       return HadError;
       
+    case MMToken::ExplicitKeyword:
     case MMToken::ModuleKeyword:
     case MMToken::FrameworkKeyword:
       parseModuleDecl();
       break;
       
-    case MMToken::ExplicitKeyword:
     case MMToken::ExportKeyword:
     case MMToken::HeaderKeyword:
     case MMToken::Identifier:

Added: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h?rev=146012&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h (added)
+++ cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/PrivateHeaders/DependsOnModulePrivate.h Tue Dec  6 20:23:45 2011
@@ -0,0 +1,2 @@
+int depends_on_module_private;
+

Added: cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map?rev=146012&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map (added)
+++ cfe/trunk/test/Modules/Inputs/DependsOnModule.framework/module_private.map Tue Dec  6 20:23:45 2011
@@ -0,0 +1,6 @@
+explicit module DependsOnModule.Private {
+  explicit module DependsOnModule {
+    header "DependsOnModulePrivate.h"
+  }
+}
+

Modified: cfe/trunk/test/Modules/auto-module-import.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/auto-module-import.m?rev=146012&r1=146011&r2=146012&view=diff
==============================================================================
--- cfe/trunk/test/Modules/auto-module-import.m (original)
+++ cfe/trunk/test/Modules/auto-module-import.m Tue Dec  6 20:23:45 2011
@@ -39,3 +39,6 @@
 void testModuleSubFrameworkAgain() {
   char *msf = module_subframework;
 }
+
+// Test inclusion of private headers.
+#include <DependsOnModule/DependsOnModulePrivate.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.Private.DependsOnModule'}}





More information about the cfe-commits mailing list