diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 70951a6531f7..286a7ef40ed4 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -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 " diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index af41d69adf10..26a0b28182ad 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -59,10 +59,24 @@ public: llvm::SmallVector 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 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( + const_cast(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. /// diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index c3a8a377c44f..97bddfa97ea1 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -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 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::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"; } diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 6d227d003e9d..164eb27e7217 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -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: diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 8d957e26335b..ebc1795a268e 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -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, diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 3e91e55228ef..d31eef9e19ad 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -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. diff --git a/clang/test/Modules/Inputs/DependsOnModule.framework/module.map b/clang/test/Modules/Inputs/DependsOnModule.framework/module.map index 99ecac8bccd2..d4c2a6706179 100644 --- a/clang/test/Modules/Inputs/DependsOnModule.framework/module.map +++ b/clang/test/Modules/Inputs/DependsOnModule.framework/module.map @@ -1,4 +1,7 @@ framework module DependsOnModule { umbrella "DependsOnModule.h" header "other.h" + module * { + export * + } }