summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-12-08 19:11:24 +0000
committerDouglas Gregor <dgregor@apple.com>2011-12-08 19:11:24 +0000
commit524e33e1f8d614926b56f83e123d915d43543c2d (patch)
tree1c44c6640b704afcd3c1c8f9914dee2f514a7969 /clang/lib
parent5780f9df56ec5efda7e40df8a88d8c6057663033 (diff)
downloadbcm5719-llvm-524e33e1f8d614926b56f83e123d915d43543c2d.tar.gz
bcm5719-llvm-524e33e1f8d614926b56f83e123d915d43543c2d.zip
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. llvm-svn: 146165
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp23
-rw-r--r--clang/lib/Lex/ModuleMap.cpp83
-rw-r--r--clang/lib/Serialization/ASTReader.cpp24
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp16
4 files changed, 132 insertions, 14 deletions
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 190cdba5820..5dabe819963 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -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 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
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.
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index e4c9d77ad69..c9efbf0b53f 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -346,6 +346,11 @@ void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
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 @@ namespace clang {
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseHeaderDecl(SourceLocation UmbrellaLoc);
+ void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
void parseInferredSubmoduleDecl(bool Explicit);
@@ -796,9 +802,14 @@ void ModuleMapParser::parseModuleDecl() {
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 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
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 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
}
} 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 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
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;
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 21be3aa50c7..236c2bd1f53 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3088,7 +3088,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
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 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
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");
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 1bd9050fe0b..83ad885969d 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1900,7 +1900,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
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 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
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 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
// 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.
OpenPOWER on IntegriCloud