[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