[cfe-commits] r146165 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/ModuleMap.h include/clang/Serialization/ASTBitCodes.h lib/Frontend/FrontendActions.cpp lib/Lex/ModuleMap.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/Modules/Inputs/normal-module-map/module.map test/Modules/Inputs/normal-module-map/nested_umbrella/ test/Modules/Inputs/normal-module-map/nested_umbrella/a.h test/Modules/Inputs/normal-module-map/nested_umbrella/b.h test/Modules/normal-module-map.cpp

Douglas Gregor dgregor at apple.com
Thu Dec 8 11:11:25 PST 2011


Author: dgregor
Date: Thu Dec  8 13:11:24 2011
New Revision: 146165

URL: http://llvm.org/viewvc/llvm-project?rev=146165&view=rev
Log:
Implement umbrella directories for modules, which are similar to
umbrella headers in the sense that all of the headers within that
directory (and eventually its subdirectories) are considered to be
part of the module with that umbrella directory. However, unlike
umbrella headers, which are expected to include all of the headers
within their subdirectories, Clang will automatically include all of
the headers it finds in the named subdirectory.

The intent here is to allow a module map to trivially turn a
subdirectory into a module, where the module's structure can mimic the
directory structure.


Added:
    cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/
    cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h   (with props)
    cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/Modules/Inputs/normal-module-map/module.map
    cfe/trunk/test/Modules/normal-module-map.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Dec  8 13:11:24 2011
@@ -382,8 +382,9 @@
 def err_mmap_expected_rbrace : Error<"expected '}'">;
 def note_mmap_lbrace_match : Note<"to match this '{'">;
 def err_mmap_expected_member : Error<
-  "expected umbrella header, header, submodule, or module export">;
+  "expected umbrella, header, submodule, or module export">;
 def err_mmap_expected_header : Error<"expected a header name after '%0'">;
+def err_mmap_expected_dir : Error<"expected a directory name after '%0'">;
 def err_mmap_module_redefinition : Error<
   "redefinition of module '%0'">;
 def note_mmap_prev_definition : Note<"previously defined here">;
@@ -391,10 +392,10 @@
   "header '%0' is already part of module '%1'">;
 def err_mmap_header_not_found : Error<
   "%select{|umbrella }0header '%1' not found">;
-def err_mmap_umbrella_header_conflict : Error<
-  "module '%0' already has an umbrella header ('%1')">;
+def err_mmap_umbrella_dir_not_found : Error<
+  "umbrella directory '%0' not found">;
 def err_mmap_umbrella_clash : Error<
-  "umbrella header for module '%0' already covers this directory">;
+  "umbrella 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<
@@ -404,7 +405,7 @@
 def err_mmap_top_level_inferred_submodule : Error<
   "only submodules may be inferred with wildcard syntax">;
 def err_mmap_inferred_no_umbrella : Error<
-  "inferred submodules require a module with an umbrella header">;
+  "inferred submodules require a module with an umbrella">;
 def err_mmap_inferred_redef : Error<
   "redefinition of inferred submodule">;
 def err_mmap_expected_lbrace_wildcard : Error<

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Dec  8 13:11:24 2011
@@ -181,7 +181,11 @@
   /// \brief Sets the umbrella header of the given module to the given
   /// header.
   void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader);
-  
+
+  /// \brief Sets the umbrella directory of the given module to the given
+  /// directory.
+  void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir);
+
   /// \brief Adds this header to the given module.
   void addHeader(Module *Mod, const FileEntry *Header);
   

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Thu Dec  8 13:11:24 2011
@@ -507,22 +507,24 @@
     
     /// \brief Record types used within a submodule description block.
     enum SubmoduleRecordTypes {
+      /// \brief Metadata for submodules as a whole.
+      SUBMODULE_METADATA = 0,
       /// \brief Defines the major attributes of a submodule, including its
       /// name and parent.
-      SUBMODULE_DEFINITION = 0,
+      SUBMODULE_DEFINITION = 1,
       /// \brief Specifies the umbrella header used to create this module,
       /// if any.
-      SUBMODULE_UMBRELLA = 1,
+      SUBMODULE_UMBRELLA_HEADER = 2,
       /// \brief Specifies a header that falls into this (sub)module.
-      SUBMODULE_HEADER = 2,
-      /// \brief Metadata for submodules as a whole.
-      SUBMODULE_METADATA = 3,
+      SUBMODULE_HEADER = 3,
+      /// \brief Specifies an umbrella directory.
+      SUBMODULE_UMBRELLA_DIR = 4,
       /// \brief Specifies the submodules that are imported by this 
       /// submodule.
-      SUBMODULE_IMPORTS = 4,
+      SUBMODULE_IMPORTS = 5,
       /// \brief Specifies the submodules that are re-exported from this 
       /// submodule.
-      SUBMODULE_EXPORTS = 5
+      SUBMODULE_EXPORTS = 6
     };
     
     /// \defgroup ASTAST AST file AST constants

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Thu Dec  8 13:11:24 2011
@@ -21,6 +21,7 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/Serialization/ASTWriter.h"
 #include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
@@ -155,6 +156,28 @@
       Includes += UmbrellaHeader->getName();
       Includes += "\"\n";
     }
+  } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
+    // Add all of the headers we find in this subdirectory (FIXME: recursively!).
+    llvm::error_code EC;
+    llvm::SmallString<128> DirNative;
+    llvm::sys::path::native(UmbrellaDir->getName(), DirNative);
+    for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+         Dir != DirEnd && !EC; Dir.increment(EC)) {
+      // Check whether this entry has an extension typically associated with 
+      // headers.
+      if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
+          .Cases(".h", ".H", ".hh", ".hpp", true)
+          .Default(false))
+        continue;
+      
+      // Include this header umbrella header for submodules.
+      if (LangOpts.ObjC1)
+        Includes += "#import \"";
+      else
+        Includes += "#include \"";
+      Includes += Dir->path();
+      Includes += "\"\n";
+    }
   }
   
   // Recurse into submodules.

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Dec  8 13:11:24 2011
@@ -346,6 +346,11 @@
   UmbrellaDirs[UmbrellaDir] = Mod;
 }
 
+void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
+  Mod->Umbrella = UmbrellaDir;
+  UmbrellaDirs[UmbrellaDir] = Mod;
+}
+
 void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
   Mod->Headers.push_back(Header);
   Headers[Header] = Mod;
@@ -494,6 +499,7 @@
     bool parseModuleId(ModuleId &Id);
     void parseModuleDecl();
     void parseHeaderDecl(SourceLocation UmbrellaLoc);
+    void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
     void parseExportDecl();
     void parseInferredSubmoduleDecl(bool Explicit);
     
@@ -796,9 +802,14 @@
       parseExportDecl();
       break;
         
-    case MMToken::UmbrellaKeyword:
-      parseHeaderDecl(consumeToken());
+    case MMToken::UmbrellaKeyword: {
+      SourceLocation UmbrellaLoc = consumeToken();
+      if (Tok.is(MMToken::HeaderKeyword))
+        parseHeaderDecl(UmbrellaLoc);
+      else
+        parseUmbrellaDirDecl(UmbrellaLoc);
       break;
+    }
         
     case MMToken::HeaderKeyword:
       parseHeaderDecl(SourceLocation());
@@ -863,11 +874,10 @@
   std::string FileName = Tok.getString();
   SourceLocation FileNameLoc = consumeToken();
   
-  // Check whether we already have an umbrella header.
-  if (Umbrella && ActiveModule->getUmbrellaHeader()) {
-    Diags.Report(FileNameLoc, diag::err_mmap_umbrella_header_conflict)
-      << ActiveModule->getFullModuleName() 
-      << ActiveModule->getUmbrellaHeader()->getName();
+  // Check whether we already have an umbrella.
+  if (Umbrella && ActiveModule->Umbrella) {
+    Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash)
+      << ActiveModule->getFullModuleName();
     HadError = true;
     return;
   }
@@ -935,9 +945,62 @@
     }
   } else {
     Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
-      << false << FileName;
+      << Umbrella << FileName;
+    HadError = true;
+  }
+}
+
+/// \brief Parse an umbrella directory declaration.
+///
+///   umbrella-dir-declaration:
+///     umbrella string-literal
+void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
+  // Parse the directory name.
+  if (!Tok.is(MMToken::StringLiteral)) {
+    Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) 
+      << "umbrella";
+    HadError = true;
+    return;
+  }
+
+  std::string DirName = Tok.getString();
+  SourceLocation DirNameLoc = consumeToken();
+  
+  // Check whether we already have an umbrella.
+  if (ActiveModule->Umbrella) {
+    Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash)
+      << ActiveModule->getFullModuleName();
+    HadError = true;
+    return;
+  }
+
+  // Look for this file.
+  const DirectoryEntry *Dir = 0;
+  if (llvm::sys::path::is_absolute(DirName))
+    Dir = SourceMgr.getFileManager().getDirectory(DirName);
+  else {
+    llvm::SmallString<128> PathName;
+    PathName = Directory->getName();
+    llvm::sys::path::append(PathName, DirName);
+    Dir = SourceMgr.getFileManager().getDirectory(PathName);
+  }
+  
+  if (!Dir) {
+    Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found)
+      << DirName;
     HadError = true;
+    return;
   }
+  
+  if (Module *OwningModule = Map.UmbrellaDirs[Dir]) {
+    Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
+      << OwningModule->getFullModuleName();
+    HadError = true;
+    return;
+  } 
+  
+  // Record this umbrella directory.
+  Map.setUmbrellaDir(ActiveModule, Dir);
 }
 
 /// \brief Parse a module export declaration.
@@ -998,8 +1061,8 @@
     Failed = true;
   }
   
-  // Inferred modules must have umbrella headers.
-  if (!Failed && !ActiveModule->getUmbrellaHeader()) {
+  // Inferred modules must have umbrella directories.
+  if (!Failed && !ActiveModule->getUmbrellaDir()) {
     Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
     Failed = true;
   }

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Dec  8 13:11:24 2011
@@ -3088,7 +3088,7 @@
       break;
     }
         
-    case SUBMODULE_UMBRELLA: {
+    case SUBMODULE_UMBRELLA_HEADER: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
         return Failure;
@@ -3129,6 +3129,28 @@
       break;      
     }
         
+    case SUBMODULE_UMBRELLA_DIR: {
+      if (First) {
+        Error("missing submodule metadata record at beginning of block");
+        return Failure;
+      }
+      
+      if (!CurrentModule)
+        break;
+      
+      StringRef DirName(BlobStart, BlobLen);
+      if (const DirectoryEntry *Umbrella
+                                  = PP.getFileManager().getDirectory(DirName)) {
+        if (!CurrentModule->getUmbrellaDir())
+          ModMap.setUmbrellaDir(CurrentModule, Umbrella);
+        else if (CurrentModule->getUmbrellaDir() != Umbrella) {
+          Error("mismatched umbrella directories in submodule");
+          return Failure;
+        }
+      }
+      break;
+    }
+        
     case SUBMODULE_METADATA: {
       if (!First) {
         Error("submodule metadata record not at beginning of block");

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Dec  8 13:11:24 2011
@@ -1900,7 +1900,7 @@
   unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
 
   Abbrev = new BitCodeAbbrev();
-  Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA));
+  Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER));
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
   unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
 
@@ -1908,7 +1908,12 @@
   Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
   unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
-  
+
+  Abbrev = new BitCodeAbbrev();
+  Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+  unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev);
+
   // Write the submodule metadata block.
   RecordData Record;
   Record.push_back(getNumberOfModules(WritingModule));
@@ -1943,9 +1948,14 @@
     // Emit the umbrella header, if there is one.
     if (const FileEntry *UmbrellaHeader = Mod->getUmbrellaHeader()) {
       Record.clear();
-      Record.push_back(SUBMODULE_UMBRELLA);
+      Record.push_back(SUBMODULE_UMBRELLA_HEADER);
       Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, 
                                 UmbrellaHeader->getName());
+    } else if (const DirectoryEntry *UmbrellaDir = Mod->getUmbrellaDir()) {
+      Record.clear();
+      Record.push_back(SUBMODULE_UMBRELLA_DIR);
+      Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, 
+                                UmbrellaDir->getName());      
     }
     
     // Emit the headers.

Modified: cfe/trunk/test/Modules/Inputs/normal-module-map/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/normal-module-map/module.map?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/normal-module-map/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/normal-module-map/module.map Thu Dec  8 13:11:24 2011
@@ -6,3 +6,8 @@
 module libB {
   header "b1.h"
 }
+
+module nested_umbrella {
+  umbrella "nested_umbrella"
+  module * { }
+}

Added: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h?rev=146165&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h (added)
+++ cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h Thu Dec  8 13:11:24 2011
@@ -0,0 +1,2 @@
+int nested_umbrella_a;
+

Propchange: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/a.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h?rev=146165&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h (added)
+++ cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h Thu Dec  8 13:11:24 2011
@@ -0,0 +1,2 @@
+int nested_umbrella_b;
+

Propchange: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Modules/Inputs/normal-module-map/nested_umbrella/b.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/Modules/normal-module-map.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/normal-module-map.cpp?rev=146165&r1=146164&r2=146165&view=diff
==============================================================================
--- cfe/trunk/test/Modules/normal-module-map.cpp (original)
+++ cfe/trunk/test/Modules/normal-module-map.cpp Thu Dec  8 13:11:24 2011
@@ -1,3 +1,5 @@
+// Note: inside the module. expected-note{{ 'nested_umbrella_a' declared here}}
+
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fauto-module-import -I %S/Inputs/normal-module-map %s -verify
 #include "Umbrella/umbrella_sub.h"
@@ -15,3 +17,19 @@
 int test() {
   return a1 + b1 + nested2;
 }
+
+__import_module__ nested_umbrella.a;
+
+int testNestedUmbrellaA() {
+  return nested_umbrella_a;
+}
+
+int testNestedUmbrellaBFail() {
+  return nested_umbrella_b; // expected-error{{use of undeclared identifier 'nested_umbrella_b'; did you mean 'nested_umbrella_a'?}}
+}
+
+__import_module__ nested_umbrella.b;
+
+int testNestedUmbrellaB() {
+  return nested_umbrella_b;
+}





More information about the cfe-commits mailing list