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">;
"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<
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<
/// \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);
/// \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
#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"
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.
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;
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseHeaderDecl(SourceLocation UmbrellaLoc);
+ void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
void parseInferredSubmoduleDecl(bool Explicit);
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());
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;
}
}
} 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.
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;
}
break;
}
- case SUBMODULE_UMBRELLA: {
+ case SUBMODULE_UMBRELLA_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
return Failure;
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");
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);
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));
// 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.
module libB {
header "b1.h"
}
+
+module nested_umbrella {
+ umbrella "nested_umbrella"
+ module * { }
+}
--- /dev/null
+int nested_umbrella_a;
+
--- /dev/null
+int nested_umbrella_b;
+
+// 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"
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;
+}