[cfe-commits] r145887 - in /cfe/trunk: include/clang/Lex/ModuleMap.h include/clang/Serialization/ASTWriter.h lib/Lex/ModuleMap.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/Modules/Inputs/Module.framework/Headers/Buried/ test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h test/Modules/Inputs/Module.framework/Headers/Module.h test/Modules/Inputs/Module.framework/Headers/Sub.h test/Modules/inferred-submodules.c

Douglas Gregor dgregor at apple.com
Mon Dec 5 17:10:29 PST 2011


Author: dgregor
Date: Mon Dec  5 19:10:29 2011
New Revision: 145887

URL: http://llvm.org/viewvc/llvm-project?rev=145887&view=rev
Log:
Implement inferred submodules support, which (when requested)
implicitly generates submodules corresponding to the headers that fall
within a module.

Added:
    cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Buried/
    cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h
    cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Sub.h
    cfe/trunk/test/Modules/inferred-submodules.c
Modified:
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/include/clang/Serialization/ASTWriter.h
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=145887&r1=145886&r2=145887&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Mon Dec  5 19:10:29 2011
@@ -177,6 +177,13 @@
   /// module owns this source location.
   Module *inferModuleFromLocation(FullSourceLoc Loc);
   
+  /// \brief Sets the umbrella header of the given module to the given
+  /// header.
+  void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader);
+  
+  /// \brief Adds this header to the given module.
+  void addHeader(Module *Mod, const FileEntry *Header);
+  
   /// \brief Parse the given module map file, and record any modules we 
   /// encounter.
   ///

Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=145887&r1=145886&r2=145887&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTWriter.h Mon Dec  5 19:10:29 2011
@@ -101,6 +101,9 @@
   /// \brief The reader of existing AST files, if we're chaining.
   ASTReader *Chain;
 
+  /// \brief The module we're currently writing, if any.
+  Module *WritingModule;
+                    
   /// \brief Indicates when the AST writing is actively performing
   /// serialization, rather than just queueing updates.
   bool WritingAST;
@@ -368,6 +371,9 @@
   /// be a positive integer.
   llvm::DenseMap<Module *, unsigned> SubmoduleIDs;
                     
+  /// \brief Retrieve or create a submodule ID for this module.
+  unsigned getSubmoduleID(Module *Mod);
+                    
   /// \brief Write the given subexpression to the bitstream.
   void WriteSubStmt(Stmt *S,
                     llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries,

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=145887&r1=145886&r2=145887&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Mon Dec  5 19:10:29 2011
@@ -93,39 +93,75 @@
     return Known->second;
   
   const DirectoryEntry *Dir = File->getDir();
-  llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
-    = UmbrellaDirs.find(Dir);
-  if (KnownDir != UmbrellaDirs.end())
-    return KnownDir->second;
-
-  // Walk up the directory hierarchy looking for umbrella headers.
   llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
   StringRef DirName = Dir->getName();
-  do {
-    // Retrieve our parent path.
-    DirName = llvm::sys::path::parent_path(DirName);
-    if (DirName.empty())
-      break;
-    
-    // Resolve the parent path to a directory entry.
-    Dir = SourceMgr->getFileManager().getDirectory(DirName);
-    if (!Dir)
-      break;
-    
-    KnownDir = UmbrellaDirs.find(Dir);
+
+  // Keep walking up the directory hierarchy, looking for a directory with
+  // an umbrella header.
+  do {    
+    llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+      = UmbrellaDirs.find(Dir);
     if (KnownDir != UmbrellaDirs.end()) {
       Module *Result = KnownDir->second;
+      Module *TopModule = Result->getTopLevelModule();
+      if (TopModule->InferSubmodules) {
+        // Infer submodules for each of the directories we found between
+        // the directory of the umbrella header and the directory where 
+        // the actual header is located.
+        
+        // For a framework module, the umbrella directory is the framework 
+        // directory, so strip off the "Headers" or "PrivateHeaders".
+        // FIXME: Should we tack on an "explicit" for PrivateHeaders? That
+        // might be what we want, but it feels like a hack.
+        unsigned LastSkippedDir = SkippedDirs.size();
+        if (LastSkippedDir && TopModule->IsFramework)
+          --LastSkippedDir;
+        
+        for (unsigned I = LastSkippedDir; I != 0; --I) {
+          // Find or create the module that corresponds to this directory name.
+          StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
+          Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
+                                      TopModule->InferExplicitSubmodules).first;
+          
+          // Associate the module and the directory.
+          UmbrellaDirs[SkippedDirs[I-1]] = Result;
+
+          // If inferred submodules export everything they import, add a 
+          // wildcard to the set of exports.
+          if (TopModule->InferExportWildcard && Result->Exports.empty())
+            Result->Exports.push_back(Module::ExportDecl(0, true));
+        }
+        
+        // Infer a submodule with the same name as this header file.
+        StringRef Name = llvm::sys::path::stem(File->getName());
+        Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
+                                    TopModule->InferExplicitSubmodules).first;
+        
+        // If inferred submodules export everything they import, add a 
+        // wildcard to the set of exports.
+        if (TopModule->InferExportWildcard && Result->Exports.empty())
+          Result->Exports.push_back(Module::ExportDecl(0, true));
+      } else {
+        // Record each of the directories we stepped through as being part of
+        // the module we found, since the umbrella header covers them all.
+        for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
+          UmbrellaDirs[SkippedDirs[I]] = Result;
+      }
       
-      // Record each of the directories we stepped through as being part of
-      // the module we found, since the umbrella header covers them all.
-      for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
-        UmbrellaDirs[SkippedDirs[I]] = Result;
-      
+      Headers[File] = Result;
       return Result;
     }
     
     SkippedDirs.push_back(Dir);
-  } while (true);
+    
+    // Retrieve our parent path.
+    DirName = llvm::sys::path::parent_path(DirName);
+    if (DirName.empty())
+      break;
+    
+    // Resolve the parent path to a directory entry.
+    Dir = SourceMgr->getFileManager().getDirectory(DirName);
+  } while (Dir);
   
   return 0;
 }
@@ -205,10 +241,31 @@
   // export *
   Result->Exports.push_back(Module::ExportDecl(0, true));
   
+  // module * { export * }
+  Result->InferSubmodules = true;
+  Result->InferExportWildcard = true;
+  
   Modules[ModuleName] = Result;
   return Result;
 }
 
+void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
+  Headers[UmbrellaHeader] = Mod;
+  Mod->UmbrellaHeader = UmbrellaHeader;
+  
+  const DirectoryEntry *UmbrellaDir = UmbrellaHeader->getDir();
+  if (Mod->IsFramework)
+    UmbrellaDir = SourceMgr->getFileManager().getDirectory(
+                    llvm::sys::path::parent_path(UmbrellaDir->getName()));
+    
+  UmbrellaDirs[UmbrellaDir] = Mod;
+}
+
+void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
+  Mod->Headers.push_back(Header);
+  Headers[Header] = Mod;
+}
+
 const FileEntry *
 ModuleMap::getContainingModuleMapFile(Module *Module) {
   if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
@@ -683,19 +740,25 @@
   // 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 (File) {
+    const DirectoryEntry *UmbrellaDir = File->getDir();
+    if (ActiveModule->IsFramework) {
+      // For framework modules, use the framework directory as the umbrella
+      // directory.
+      UmbrellaDir = SourceMgr.getFileManager().getDirectory(
+                      llvm::sys::path::parent_path(UmbrellaDir->getName()));
+    }
+    
     if (const Module *OwningModule = Map.Headers[File]) {
       Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
         << FileName << OwningModule->getFullModuleName();
       HadError = true;
-    } else if ((OwningModule = Map.UmbrellaDirs[Directory])) {
+    } else if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
       Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
         << OwningModule->getFullModuleName();
       HadError = true;
     } else {
       // Record this umbrella header.
-      ActiveModule->UmbrellaHeader = File;
-      Map.Headers[File] = ActiveModule;
-      Map.UmbrellaDirs[Directory] = ActiveModule;
+      Map.setUmbrellaHeader(ActiveModule, File);
     }
   } else {
     Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
@@ -743,8 +806,7 @@
       HadError = true;
     } else {
       // Record this file.
-      ActiveModule->Headers.push_back(File);      
-      Map.Headers[File] = ActiveModule;
+      Map.addHeader(ActiveModule, File);
     }
   } else {
     Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=145887&r1=145886&r2=145887&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Dec  5 19:10:29 2011
@@ -3049,18 +3049,19 @@
         return Failure;
       }
 
-      if (Record.size() < 6) {
+      if (Record.size() < 7) {
         Error("malformed module definition");
         return Failure;
       }
       
       StringRef Name(BlobStart, BlobLen);
-      unsigned Parent = getGlobalSubmoduleID(F, Record[0]);
-      bool IsFramework = Record[1];
-      bool IsExplicit = Record[2];
-      bool InferSubmodules = Record[3];
-      bool InferExplicitSubmodules = Record[4];
-      bool InferExportWildcard = Record[5];
+      SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
+      SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
+      bool IsFramework = Record[2];
+      bool IsExplicit = Record[3];
+      bool InferSubmodules = Record[4];
+      bool InferExplicitSubmodules = Record[5];
+      bool InferExportWildcard = Record[6];
       
       Module *ParentModule = 0;
       if (Parent)
@@ -3071,9 +3072,9 @@
       CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, 
                                                 IsFramework, 
                                                 IsExplicit).first;
-      
-      if (CurrentModuleGlobalIndex >= SubmodulesLoaded.size() ||
-          SubmodulesLoaded[CurrentModuleGlobalIndex]) {
+      SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
+      if (GlobalIndex >= SubmodulesLoaded.size() ||
+          SubmodulesLoaded[GlobalIndex]) {
         Error("too many submodules");
         return Failure;
       }
@@ -3082,11 +3083,9 @@
       CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
       CurrentModule->InferExportWildcard = InferExportWildcard;
       if (DeserializationListener)
-        DeserializationListener->ModuleRead(
-          CurrentModuleGlobalIndex + NUM_PREDEF_SUBMODULE_IDS, 
-          CurrentModule);
+        DeserializationListener->ModuleRead(GlobalID, CurrentModule);
       
-      SubmodulesLoaded[CurrentModuleGlobalIndex++] = CurrentModule;
+      SubmodulesLoaded[GlobalIndex] = CurrentModule;
       break;
     }
         
@@ -3102,7 +3101,7 @@
       StringRef FileName(BlobStart, BlobLen);
       if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
         if (!CurrentModule->UmbrellaHeader)
-          CurrentModule->UmbrellaHeader = Umbrella;
+          ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
         else if (CurrentModule->UmbrellaHeader != Umbrella) {
           Error("mismatched umbrella headers in submodule");
           return Failure;
@@ -3126,7 +3125,7 @@
         if (std::find(CurrentModule->Headers.begin(), 
                       CurrentModule->Headers.end(), 
                       File) == CurrentModule->Headers.end())
-          CurrentModule->Headers.push_back(File);
+          ModMap.addHeader(CurrentModule, File);
       }
       break;      
     }

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=145887&r1=145886&r2=145887&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Dec  5 19:10:29 2011
@@ -1845,6 +1845,14 @@
   }
 }
 
+unsigned ASTWriter::getSubmoduleID(Module *Mod) {
+  llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);
+  if (Known != SubmoduleIDs.end())
+    return Known->second;
+  
+  return SubmoduleIDs[Mod] = NextSubmoduleID++;
+}
+
 /// \brief Compute the number of modules within the given tree (including the
 /// given module).
 static unsigned getNumberOfModules(Module *Mod) {
@@ -1881,6 +1889,7 @@
   using namespace llvm;
   BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
   Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
@@ -1912,12 +1921,12 @@
   while (!Q.empty()) {
     Module *Mod = Q.front();
     Q.pop();
-    assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end());
-    SubmoduleIDs[Mod] = NextSubmoduleID++;
+    unsigned ID = getSubmoduleID(Mod);
     
     // Emit the definition of the block.
     Record.clear();
     Record.push_back(SUBMODULE_DEFINITION);
+    Record.push_back(ID);
     if (Mod->Parent) {
       assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
       Record.push_back(SubmoduleIDs[Mod->Parent]);
@@ -1988,11 +1997,14 @@
   }
   
   Stream.ExitBlock();
+  
+  assert((NextSubmoduleID - FirstSubmoduleID
+            == getNumberOfModules(WritingModule)) && "Wrong # of submodules");
 }
 
 serialization::SubmoduleID 
 ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
-  if (Loc.isInvalid() || SubmoduleIDs.empty())
+  if (Loc.isInvalid() || !WritingModule)
     return 0; // No submodule
     
   // Find the module that owns this location.
@@ -2002,13 +2014,11 @@
   if (!OwningMod)
     return 0;
   
-  // Check whether we known about this submodule.
-  llvm::DenseMap<Module *, unsigned>::iterator Known
-    = SubmoduleIDs.find(OwningMod);
-  if (Known == SubmoduleIDs.end())
+  // Check whether this submodule is part of our own module.
+  if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
     return 0;
   
-  return Known->second;
+  return getSubmoduleID(OwningMod);
 }
 
 void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
@@ -2933,7 +2943,8 @@
 }
 
 ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
-  : Stream(Stream), Context(0), PP(0), Chain(0), WritingAST(false),
+  : Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0),
+    WritingAST(false),
     FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
     FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
     FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), 
@@ -2975,9 +2986,11 @@
 
   Context = &SemaRef.Context;
   PP = &SemaRef.PP;
+  this->WritingModule = WritingModule;
   WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule);
   Context = 0;
   PP = 0;
+  this->WritingModule = 0;
   
   WritingAST = false;
 }
@@ -3201,10 +3214,6 @@
   AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
   AddTypeRef(Context.getucontext_tType(), SpecialTypes);
 
-  // If we're emitting a module, write out the submodule information.  
-  if (WritingModule)
-    WriteSubmodules(WritingModule);
-
   // Keep writing types and declarations until all types and
   // declarations have been written.
   Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
@@ -3282,6 +3291,10 @@
 
   WriteCXXBaseSpecifiersOffsets();
   
+  // If we're emitting a module, write out the submodule information.  
+  if (WritingModule)
+    WriteSubmodules(WritingModule);
+
   Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
 
   /// Build a record containing first declarations from a chained PCH and the

Added: cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h?rev=145887&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h (added)
+++ cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Buried/Treasure.h Mon Dec  5 19:10:29 2011
@@ -0,0 +1 @@
+unsigned *Buried_Treasure;

Modified: cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h?rev=145887&r1=145886&r2=145887&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h (original)
+++ cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Module.h Mon Dec  5 19:10:29 2011
@@ -14,4 +14,7 @@
 #define MODULE_H_MACRO 1
 #__private_macro__ MODULE_H_MACRO
 
+#include <Module/Sub.h>
+#include <Module/Buried/Treasure.h>
+
 #endif // MODULE_H

Added: cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Sub.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Sub.h?rev=145887&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Sub.h (added)
+++ cfe/trunk/test/Modules/Inputs/Module.framework/Headers/Sub.h Mon Dec  5 19:10:29 2011
@@ -0,0 +1,2 @@
+int *Module_Sub;
+

Added: cfe/trunk/test/Modules/inferred-submodules.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/inferred-submodules.c?rev=145887&view=auto
==============================================================================
--- cfe/trunk/test/Modules/inferred-submodules.c (added)
+++ cfe/trunk/test/Modules/inferred-submodules.c Mon Dec  5 19:10:29 2011
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
+
+__import_module__ Module.Sub;
+
+void test_Module_Sub() {
+  int *ip = Module_Sub;
+}
+
+__import_module__ Module.Buried.Treasure;
+
+void dig() {
+  unsigned *up = Buried_Treasure;
+}
+





More information about the cfe-commits mailing list