Author: dgregor Date: Thu Sep 14 16:38:44 2017 New Revision: 313316 URL: http://llvm.org/viewvc/llvm-project?rev=313316&view=rev Log: [Module map] Introduce a private module re-export directive.
Introduce a new "export_as" directive for top-level modules, which indicates that the current module is a "private" module whose symbols will eventually be exported through the named "public" module. This is in support of a common pattern in the Darwin ecosystem where a single public framework is constructed of several private frameworks, with (currently) header duplication and some support from the linker. Addresses rdar://problem/34438420. Added: cfe/trunk/test/Modules/Inputs/export_as_test.modulemap cfe/trunk/test/Modules/export_as_test.c Modified: cfe/trunk/docs/Modules.rst cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td cfe/trunk/include/clang/Basic/Module.h cfe/trunk/include/clang/Serialization/ASTBitCodes.h cfe/trunk/lib/Basic/Module.cpp cfe/trunk/lib/Lex/ModuleMap.cpp cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp Modified: cfe/trunk/docs/Modules.rst URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/Modules.rst?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/docs/Modules.rst (original) +++ cfe/trunk/docs/Modules.rst Thu Sep 14 16:38:44 2017 @@ -323,11 +323,12 @@ Module map files use a simplified form o .. parsed-literal:: - ``config_macros`` ``export`` ``private`` + ``config_macros`` ``export_as`` ``private`` ``conflict`` ``framework`` ``requires`` ``exclude`` ``header`` ``textual`` ``explicit`` ``link`` ``umbrella`` ``extern`` ``module`` ``use`` + ``export`` Module map file --------------- @@ -387,6 +388,7 @@ Modules can have a number of different k *umbrella-dir-declaration* *submodule-declaration* *export-declaration* + *export-as-declaration* *use-declaration* *link-declaration* *config-macros-declaration* @@ -666,6 +668,31 @@ Note that, if ``Derived.h`` includes ``B compatibility for programs that rely on transitive inclusion (i.e., all of them). +Re-export Declaration +~~~~~~~~~~~~~~~~~~ +An *export-as-declaration* specifies that the current module is a private +module whose interface will be re-exported by the named public module. + +.. parsed-literal:: + + *export-as-declaration*: + ``export_as`` *identifier* + +The *export-as-declaration* names the public module that the current +(private) module will be re-exported through. Only top-level modules +can be re-exported, and any given module may only be re-exported +through a single public module. + +**Example:** In the following example, the (private) module +``MyFrameworkCore`` will be re-exported via the public module +``MyFramework``: + +.. parsed-literal:: + + module MyFrameworkCore { + export_as MyFramework + } + Use declaration ~~~~~~~~~~~~~~~ A *use-declaration* specifies another module that the current top-level module Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Sep 14 16:38:44 2017 @@ -674,6 +674,13 @@ def err_mmap_invalid_header_attribute_va "expected integer literal as value for header attribute '%0'">; def err_mmap_expected_header_attribute : Error< "expected a header attribute name ('size' or 'mtime')">; +def err_mmap_conflicting_export_as : Error< + "conflicting re-export of module '%0' as '%1' or '%2'">; +def warn_mmap_redundant_export_as : Warning< + "module '%0' already re-exported as '%1'">, + InGroup<PrivateModule>; +def err_mmap_submodule_export_as : Error< + "only top-level modules can be re-exported as public">; def warn_auto_module_import : Warning< "treating #%select{include|import|include_next|__include_macros}0 as an " Modified: cfe/trunk/include/clang/Basic/Module.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Module.h (original) +++ cfe/trunk/include/clang/Basic/Module.h Thu Sep 14 16:38:44 2017 @@ -99,6 +99,10 @@ public: /// \brief The name of the umbrella entry, as written in the module map. std::string UmbrellaAsWritten; + + /// \brief The module through which entities defined in this module will + /// eventually be exposed, for use in "private" modules. + std::string ExportAsModule; private: /// \brief The submodules of this module, indexed by name. Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original) +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Thu Sep 14 16:38:44 2017 @@ -716,6 +716,9 @@ namespace clang { /// \brief Specifies some declarations with initializers that must be /// emitted to initialize the module. SUBMODULE_INITIALIZERS = 16, + /// \brief Specifies the name of the module that will eventually + /// re-export the entities in this module. + SUBMODULE_EXPORT_AS = 17, }; /// \brief Record types used within a comments block. Modified: cfe/trunk/lib/Basic/Module.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/lib/Basic/Module.cpp (original) +++ cfe/trunk/lib/Basic/Module.cpp Thu Sep 14 16:38:44 2017 @@ -440,6 +440,11 @@ void Module::print(raw_ostream &OS, unsi } } + if (!ExportAsModule.empty()) { + OS.indent(Indent + 2); + OS << "export_as" << ExportAsModule << "\n"; + } + for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end(); MI != MIEnd; ++MI) // Print inferred subframework modules so that we don't need to re-infer Modified: cfe/trunk/lib/Lex/ModuleMap.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/lib/Lex/ModuleMap.cpp (original) +++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Sep 14 16:38:44 2017 @@ -1201,6 +1201,7 @@ namespace clang { ExcludeKeyword, ExplicitKeyword, ExportKeyword, + ExportAsKeyword, ExternKeyword, FrameworkKeyword, LinkKeyword, @@ -1312,6 +1313,7 @@ namespace clang { SourceLocation LeadingLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); + void parseExportAsDecl(); void parseUseDecl(); void parseLinkDecl(); void parseConfigMacros(); @@ -1363,6 +1365,7 @@ retry: .Case("exclude", MMToken::ExcludeKeyword) .Case("explicit", MMToken::ExplicitKeyword) .Case("export", MMToken::ExportKeyword) + .Case("export_as", MMToken::ExportAsKeyword) .Case("extern", MMToken::ExternKeyword) .Case("framework", MMToken::FrameworkKeyword) .Case("header", MMToken::HeaderKeyword) @@ -1590,6 +1593,7 @@ namespace { /// header-declaration /// submodule-declaration /// export-declaration +/// export-as-declaration /// link-declaration /// /// submodule-declaration: @@ -1824,6 +1828,10 @@ void ModuleMapParser::parseModuleDecl() parseExportDecl(); break; + case MMToken::ExportAsKeyword: + parseExportAsDecl(); + break; + case MMToken::UseKeyword: parseUseDecl(); break; @@ -2284,6 +2292,41 @@ void ModuleMapParser::parseExportDecl() ActiveModule->UnresolvedExports.push_back(Unresolved); } +/// \brief Parse a module export_as declaration. +/// +/// export-as-declaration: +/// 'export_as' identifier +void ModuleMapParser::parseExportAsDecl() { + assert(Tok.is(MMToken::ExportAsKeyword)); + consumeToken(); + + if (!Tok.is(MMToken::Identifier)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_module_id); + HadError = true; + return; + } + + if (ActiveModule->Parent) { + Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as); + consumeToken(); + return; + } + + if (!ActiveModule->ExportAsModule.empty()) { + if (ActiveModule->ExportAsModule == Tok.getString()) { + Diags.Report(Tok.getLocation(), diag::warn_mmap_redundant_export_as) + << ActiveModule->Name << Tok.getString(); + } else { + Diags.Report(Tok.getLocation(), diag::err_mmap_conflicting_export_as) + << ActiveModule->Name << ActiveModule->ExportAsModule + << Tok.getString(); + } + } + + ActiveModule->ExportAsModule = Tok.getString(); + consumeToken(); +} + /// \brief Parse a module use declaration. /// /// use-declaration: @@ -2689,6 +2732,7 @@ bool ModuleMapParser::parseModuleMapFile case MMToken::Exclaim: case MMToken::ExcludeKeyword: case MMToken::ExportKeyword: + case MMToken::ExportAsKeyword: case MMToken::HeaderKeyword: case MMToken::Identifier: case MMToken::LBrace: Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Sep 14 16:38:44 2017 @@ -5123,7 +5123,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile break; } - case SUBMODULE_INITIALIZERS: + case SUBMODULE_INITIALIZERS: { if (!ContextObj) break; SmallVector<uint32_t, 16> Inits; @@ -5132,6 +5132,11 @@ ASTReader::ReadSubmoduleBlock(ModuleFile ContextObj->addLazyModuleInitializers(CurrentModule, Inits); break; } + + case SUBMODULE_EXPORT_AS: + CurrentModule->ExportAsModule = Blob.str(); + break; + } } } Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=313316&r1=313315&r2=313316&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Sep 14 16:38:44 2017 @@ -1130,6 +1130,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(SUBMODULE_TEXTUAL_HEADER); RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER); RECORD(SUBMODULE_INITIALIZERS); + RECORD(SUBMODULE_EXPORT_AS); // Comments Block. BLOCK(COMMENTS_BLOCK); @@ -2791,6 +2792,12 @@ void ASTWriter::WriteSubmodules(Module * Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + Abbrev = std::make_shared<BitCodeAbbrev>(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXPORT_AS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name + unsigned ExportAsAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); + + // Write the submodule metadata block. RecordData::value_type Record[] = { getNumberOfModules(WritingModule), @@ -2925,6 +2932,12 @@ void ASTWriter::WriteSubmodules(Module * if (!Inits.empty()) Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits); + // Emit the name of the re-exported module, if any. + if (!Mod->ExportAsModule.empty()) { + RecordData::value_type Record[] = {SUBMODULE_EXPORT_AS}; + Stream.EmitRecordWithBlob(ExportAsAbbrev, Record, Mod->ExportAsModule); + } + // Queue up the submodules of this module. for (auto *M : Mod->submodules()) Q.push(M); Added: cfe/trunk/test/Modules/Inputs/export_as_test.modulemap URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/export_as_test.modulemap?rev=313316&view=auto ============================================================================== --- cfe/trunk/test/Modules/Inputs/export_as_test.modulemap (added) +++ cfe/trunk/test/Modules/Inputs/export_as_test.modulemap Thu Sep 14 16:38:44 2017 @@ -0,0 +1,9 @@ +module PrivateFoo { + export_as Foo + export_as Bar + export_as Bar + + module Sub { + export_as Wibble + } +} Added: cfe/trunk/test/Modules/export_as_test.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/export_as_test.c?rev=313316&view=auto ============================================================================== --- cfe/trunk/test/Modules/export_as_test.c (added) +++ cfe/trunk/test/Modules/export_as_test.c Thu Sep 14 16:38:44 2017 @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/export_as_test.modulemap %s 2> %t.err +// RUN: FileCheck %s < %t.err + +// CHECK: export_as_test.modulemap:3:13: error: conflicting re-export of module 'PrivateFoo' as 'Foo' or 'Bar' +// CHECK: export_as_test.modulemap:4:13: warning: module 'PrivateFoo' already re-exported as 'Bar' +// CHECK: export_as_test.modulemap:7:15: error: only top-level modules can be re-exported as public + + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits