Parse inferred submodules in module maps, track their contents in

Module, and (de-)serialize this information. Semantics of inferred
submodules to follow.

llvm-svn: 145864
This commit is contained in:
Douglas Gregor 2011-12-05 22:27:44 +00:00
parent b8c719ccc6
commit 734410916a
7 changed files with 197 additions and 17 deletions

View File

@ -384,7 +384,7 @@ def err_mmap_expected_lbrace : Error<"expected '{' to start module '%0'">;
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, or submodule">;
"expected umbrella header, header, submodule, or module export">;
def err_mmap_expected_header : Error<"expected a header name after '%0'">;
def err_mmap_module_redefinition : Error<
"redefinition of module '%0'">;
@ -405,6 +405,18 @@ def err_mmap_missing_module_unqualified : Error<
"no module named '%0' visible from '%1'">;
def err_mmap_missing_module_qualified : Error<
"no module named '%0' in '%1'">;
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">;
def err_mmap_inferred_redef : Error<
"redefinition of inferred submodule">;
def err_mmap_expected_lbrace_wildcard : Error<
"expected '{' to start inferred submodule">;
def err_mmap_expected_wildcard_member : Error<
"expected module export wildcard">;
def err_mmap_expected_export_wildcard : Error<
"only '*' can be exported from an inferred submodule">;
def warn_auto_module_import : Warning<
"treating #%select{include|import|include_next|__include_macros}0 as an "

View File

@ -59,10 +59,24 @@ public:
llvm::SmallVector<const FileEntry *, 2> Headers;
/// \brief Whether this is a framework module.
bool IsFramework;
unsigned IsFramework : 1;
/// \brief Whether this is an explicit submodule.
bool IsExplicit;
unsigned IsExplicit : 1;
/// \brief Whether we should infer submodules for this module based on
/// the headers.
///
/// Submodules can only be inferred for modules with an umbrella header.
unsigned InferSubmodules : 1;
/// \brief Whether, when inferring submodules, the inferred submodules
/// should be explicit.
unsigned InferExplicitSubmodules : 1;
/// \brief Whether, when inferring submodules, the inferr submodules should
/// export all modules they import (e.g., the equivalent of "export *").
unsigned InferExportWildcard : 1;
/// \brief Describes the visibility of the various names within a
/// particular module.
@ -79,6 +93,9 @@ public:
///\ brief The visibility of names within this particular module.
NameVisibilityKind NameVisibility;
/// \brief The location of the inferred submodule.
SourceLocation InferredSubmoduleLoc;
/// \brief The set of modules imported by this module, and on which this
/// module depends.
llvm::SmallVector<Module *, 2> Imports;
@ -114,14 +131,17 @@ public:
explicit Module(StringRef Name, SourceLocation DefinitionLoc,
bool IsFramework)
: Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), UmbrellaHeader(0),
IsFramework(IsFramework), IsExplicit(false), NameVisibility(Hidden) { }
IsFramework(IsFramework), IsExplicit(false), InferSubmodules(false),
InferExplicitSubmodules(false), InferExportWildcard(false),
NameVisibility(Hidden) { }
/// \brief Construct a new module or submodule.
Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
bool IsFramework, bool IsExplicit)
: Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
UmbrellaHeader(0), IsFramework(IsFramework), IsExplicit(IsExplicit),
NameVisibility(Hidden) { }
InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false),NameVisibility(Hidden) { }
~Module();
@ -146,10 +166,23 @@ public:
/// \brief Retrieve the full name of this module, including the path from
/// its top-level module.
std::string getFullModuleName() const;
/// \brief Retrieve the top-level module for this (sub)module, which may
/// be this module.
Module *getTopLevelModule() {
return const_cast<Module *>(
const_cast<const Module *>(this)->getTopLevelModule());
}
/// \brief Retrieve the top-level module for this (sub)module, which may
/// be this module.
const Module *getTopLevelModule() const;
/// \brief Retrieve the name of the top-level module.
///
StringRef getTopLevelModuleName() const;
StringRef getTopLevelModuleName() const {
return getTopLevelModule()->Name;
}
/// \brief Print the module map for this module to the given stream.
///

View File

@ -37,6 +37,14 @@ bool Module::isSubModuleOf(Module *Other) const {
return false;
}
const Module *Module::getTopLevelModule() const {
const Module *Result = this;
while (Result->Parent)
Result = Result->Parent;
return Result;
}
std::string Module::getFullModuleName() const {
llvm::SmallVector<StringRef, 2> Names;
@ -57,14 +65,6 @@ std::string Module::getFullModuleName() const {
return Result;
}
StringRef Module::getTopLevelModuleName() const {
const Module *Top = this;
while (Top->Parent)
Top = Top->Parent;
return Top->Name;
}
static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
if (I)
@ -96,7 +96,7 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
}
for (llvm::StringMap<Module *>::const_iterator MI = SubModules.begin(),
MIEnd = SubModules.end();
MIEnd = SubModules.end();
MI != MIEnd; ++MI)
MI->getValue()->print(OS, Indent + 2);
@ -126,6 +126,19 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS << "\n";
}
if (InferSubmodules) {
OS.indent(Indent + 2);
if (InferExplicitSubmodules)
OS << "explicit ";
OS << "module * {\n";
if (InferExportWildcard) {
OS.indent(Indent + 4);
OS << "export *\n";
}
OS.indent(Indent + 2);
OS << "}\n";
}
OS.indent(Indent);
OS << "}\n";
}

View File

@ -351,6 +351,7 @@ namespace clang {
void parseUmbrellaDecl();
void parseHeaderDecl();
void parseExportDecl();
void parseInferredSubmoduleDecl(bool Explicit);
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
@ -485,8 +486,12 @@ void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
/// module-member:
/// umbrella-declaration
/// header-declaration
/// 'explicit'[opt] module-declaration
/// 'explicit'[opt] submodule-declaration
/// export-declaration
///
/// submodule-declaration:
/// module-declaration
/// inferred-submodule-declaration
void ModuleMapParser::parseModuleDecl() {
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
Tok.is(MMToken::FrameworkKeyword));
@ -514,6 +519,11 @@ void ModuleMapParser::parseModuleDecl() {
return;
}
consumeToken(); // 'module' keyword
// If we have a wildcard for the module name, this is an inferred submodule.
// Parse it.
if (Tok.is(MMToken::Star))
return parseInferredSubmoduleDecl(Explicit);
// Parse the module name.
if (!Tok.is(MMToken::Identifier)) {
@ -790,6 +800,98 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
assert(Tok.is(MMToken::Star));
SourceLocation StarLoc = consumeToken();
bool Failed = false;
// Inferred modules must be submodules.
if (!ActiveModule) {
Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
Failed = true;
}
// Inferred modules must have umbrella headers.
if (!Failed && !ActiveModule->getTopLevelModule()->UmbrellaHeader) {
Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
Failed = true;
}
// Check for redefinition of an inferred module.
if (!Failed && ActiveModule->getTopLevelModule()->InferSubmodules) {
Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
if (ActiveModule->getTopLevelModule()->InferredSubmoduleLoc.isValid())
Diags.Report(ActiveModule->getTopLevelModule()->InferredSubmoduleLoc,
diag::note_mmap_prev_definition);
Failed = true;
}
// If there were any problems with this inferred submodule, skip its body.
if (Failed) {
if (Tok.is(MMToken::LBrace)) {
consumeToken();
skipUntil(MMToken::RBrace);
if (Tok.is(MMToken::RBrace))
consumeToken();
}
HadError = true;
return;
}
// Note that we have an inferred submodule.
Module *TopModule = ActiveModule->getTopLevelModule();
TopModule->InferSubmodules = true;
TopModule->InferredSubmoduleLoc = StarLoc;
TopModule->InferExplicitSubmodules = Explicit;
// Parse the opening brace.
if (!Tok.is(MMToken::LBrace)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);
HadError = true;
return;
}
SourceLocation LBraceLoc = consumeToken();
// Parse the body of the inferred submodule.
bool Done = false;
do {
switch (Tok.Kind) {
case MMToken::EndOfFile:
case MMToken::RBrace:
Done = true;
break;
case MMToken::ExportKeyword: {
consumeToken();
if (Tok.is(MMToken::Star))
TopModule->InferExportWildcard = true;
else
Diags.Report(Tok.getLocation(),
diag::err_mmap_expected_export_wildcard);
consumeToken();
break;
}
case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword:
case MMToken::HeaderKeyword:
case MMToken::UmbrellaKeyword:
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_wildcard_member);
consumeToken();
break;
}
} while (!Done);
if (Tok.is(MMToken::RBrace))
consumeToken();
else {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
HadError = true;
}
}
/// \brief Parse a module map file.
///
/// module-map-file:

View File

@ -3049,11 +3049,19 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return Failure;
}
if (Record.size() < 6) {
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];
Module *ParentModule = 0;
if (Parent)
ParentModule = getSubmodule(Parent);
@ -3070,6 +3078,9 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return Failure;
}
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
if (DeserializationListener)
DeserializationListener->ModuleRead(
CurrentModuleGlobalIndex + NUM_PREDEF_SUBMODULE_IDS,

View File

@ -1884,6 +1884,9 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
@ -1923,6 +1926,9 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}
Record.push_back(Mod->IsFramework);
Record.push_back(Mod->IsExplicit);
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the umbrella header, if there is one.

View File

@ -1,4 +1,7 @@
framework module DependsOnModule {
umbrella "DependsOnModule.h"
header "other.h"
module * {
export *
}
}