From 5f0a3524d184f7fcda856aaa17686064e45cacd3 Mon Sep 17 00:00:00 2001 From: Daniel Jasper <djasper@google.com> Date: Wed, 11 Sep 2013 07:20:44 +0000 Subject: [PATCH] Support for modular module-map-files This patch is the first step to make module-map-files modular (instead of requiring a single "module.map"-file per include directory). This step adds a new "extern module" declaration that enables module-map-files to reference one another along with a very basic implementation. The next steps are: * Combine this with the use-declaration (from http://llvm-reviews.chandlerc.com/D1546) in order to only load module map files required for a specific compilation. * Add an additional flag to start with a specific module-map-file (instead of requiring there to be at least one "module.map"). Review: http://llvm-reviews.chandlerc.com/D1637 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190497 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/Modules.rst | 4 ++ include/clang/Basic/DiagnosticLexKinds.td | 1 + lib/Lex/ModuleMap.cpp | 59 +++++++++++++++++++- test/Modules/Inputs/modular_maps/a.h | 4 ++ test/Modules/Inputs/modular_maps/b.h | 4 ++ test/Modules/Inputs/modular_maps/module.map | 6 ++ test/Modules/Inputs/modular_maps/moduleb.map | 3 + test/Modules/modular_maps.cpp | 6 ++ 8 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 test/Modules/Inputs/modular_maps/a.h create mode 100644 test/Modules/Inputs/modular_maps/b.h create mode 100644 test/Modules/Inputs/modular_maps/module.map create mode 100644 test/Modules/Inputs/modular_maps/moduleb.map create mode 100644 test/Modules/modular_maps.cpp diff --git a/docs/Modules.rst b/docs/Modules.rst index c086644ee3f..8c20301315c 100644 --- a/docs/Modules.rst +++ b/docs/Modules.rst @@ -238,6 +238,7 @@ Module map files use a simplified form of the C99 lexer, with the same rules for ``conflict`` ``framework`` ``requires`` ``exclude`` ``header`` ``private`` ``explicit`` ``link`` ``umbrella`` + ``extern`` Module map file --------------- @@ -263,6 +264,7 @@ A module declaration describes a module, including the headers that contribute t *module-declaration*: ``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}' + ``extern`` ``module`` *module-id* *string-literal* The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition. @@ -295,6 +297,8 @@ Modules can have a number of different kinds of members, each of which is descri *config-macros-declaration* *conflict-declaration* +An extern module references a module defined by the *module-id* in a file given by the *string-literal*. The file can be referenced either by an absolute path or by a path relative to the current map file. + Requires declaration ~~~~~~~~~~~~~~~~~~~~ A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module. diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 41ec81ca260..f1c8a09dee6 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -527,6 +527,7 @@ def note_mmap_lsquare_match : Note<"to match this ']'">; def err_mmap_expected_member : Error< "expected umbrella, header, submodule, or module export">; def err_mmap_expected_header : Error<"expected a header name after '%0'">; +def err_mmap_expected_mmap_file : Error<"expected a module map file name">; def err_mmap_module_redefinition : Error< "redefinition of module '%0'">; def note_mmap_prev_definition : Note<"previously defined here">; diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index d411ead7e96..b2698b1877d 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -722,6 +722,7 @@ namespace clang { ExcludeKeyword, ExplicitKeyword, ExportKeyword, + ExternKeyword, FrameworkKeyword, LinkKeyword, ModuleKeyword, @@ -814,6 +815,7 @@ namespace clang { typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId; bool parseModuleId(ModuleId &Id); void parseModuleDecl(); + void parseExternModuleDecl(); void parseRequiresDecl(); void parseHeaderDecl(clang::MMToken::TokenKind, SourceLocation LeadingLoc); @@ -865,6 +867,7 @@ retry: .Case("exclude", MMToken::ExcludeKeyword) .Case("explicit", MMToken::ExplicitKeyword) .Case("export", MMToken::ExportKeyword) + .Case("extern", MMToken::ExternKeyword) .Case("framework", MMToken::FrameworkKeyword) .Case("header", MMToken::HeaderKeyword) .Case("link", MMToken::LinkKeyword) @@ -1033,6 +1036,7 @@ namespace { /// \brief Parse a module declaration. /// /// module-declaration: +/// 'extern' 'module' module-id string-literal /// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt] /// { module-member* } /// @@ -1048,7 +1052,12 @@ namespace { /// inferred-submodule-declaration void ModuleMapParser::parseModuleDecl() { assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) || - Tok.is(MMToken::FrameworkKeyword)); + Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword)); + if (Tok.is(MMToken::ExternKeyword)) { + parseExternModuleDecl(); + return; + } + // Parse 'explicit' or 'framework' keyword, if present. SourceLocation ExplicitLoc; bool Explicit = false; @@ -1193,11 +1202,12 @@ void ModuleMapParser::parseModuleDecl() { break; case MMToken::ExplicitKeyword: + case MMToken::ExternKeyword: case MMToken::FrameworkKeyword: case MMToken::ModuleKeyword: parseModuleDecl(); break; - + case MMToken::ExportKeyword: parseExportDecl(); break; @@ -1271,6 +1281,50 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule = PreviousActiveModule; } +/// \brief Parse an extern module declaration. +/// +/// extern module-declaration: +/// 'extern' 'module' module-id string-literal +void ModuleMapParser::parseExternModuleDecl() { + assert(Tok.is(MMToken::ExternKeyword)); + consumeToken(); // 'extern' keyword + + // Parse 'module' keyword. + if (!Tok.is(MMToken::ModuleKeyword)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); + consumeToken(); + HadError = true; + return; + } + consumeToken(); // 'module' keyword + + // Parse the module name. + ModuleId Id; + if (parseModuleId(Id)) { + HadError = true; + return; + } + + // Parse the referenced module map file name. + if (!Tok.is(MMToken::StringLiteral)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file); + HadError = true; + return; + } + std::string FileName = Tok.getString(); + consumeToken(); // filename + + StringRef FileNameRef = FileName; + SmallString<128> ModuleMapFileName; + if (llvm::sys::path::is_relative(FileNameRef)) { + ModuleMapFileName += Directory->getName(); + llvm::sys::path::append(ModuleMapFileName, FileName); + FileNameRef = ModuleMapFileName.str(); + } + if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef)) + Map.parseModuleMapFile(File, /*IsSystem=*/false); +} + /// \brief Parse a requires declaration. /// /// requires-declaration: @@ -1925,6 +1979,7 @@ bool ModuleMapParser::parseModuleMapFile() { return HadError; case MMToken::ExplicitKeyword: + case MMToken::ExternKeyword: case MMToken::ModuleKeyword: case MMToken::FrameworkKeyword: parseModuleDecl(); diff --git a/test/Modules/Inputs/modular_maps/a.h b/test/Modules/Inputs/modular_maps/a.h new file mode 100644 index 00000000000..a36dc1b59d6 --- /dev/null +++ b/test/Modules/Inputs/modular_maps/a.h @@ -0,0 +1,4 @@ +#ifndef A_H +#define A_H +const int a = 2; +#endif diff --git a/test/Modules/Inputs/modular_maps/b.h b/test/Modules/Inputs/modular_maps/b.h new file mode 100644 index 00000000000..55daf728680 --- /dev/null +++ b/test/Modules/Inputs/modular_maps/b.h @@ -0,0 +1,4 @@ +#ifndef B_H +#define B_H +const int b = 3; +#endif diff --git a/test/Modules/Inputs/modular_maps/module.map b/test/Modules/Inputs/modular_maps/module.map new file mode 100644 index 00000000000..7018c413042 --- /dev/null +++ b/test/Modules/Inputs/modular_maps/module.map @@ -0,0 +1,6 @@ +module A { + header "a.h" +} + +extern module B "moduleb.map" + diff --git a/test/Modules/Inputs/modular_maps/moduleb.map b/test/Modules/Inputs/modular_maps/moduleb.map new file mode 100644 index 00000000000..6f36ccd3baa --- /dev/null +++ b/test/Modules/Inputs/modular_maps/moduleb.map @@ -0,0 +1,3 @@ +module B { + private header "b.h" +} diff --git a/test/Modules/modular_maps.cpp b/test/Modules/modular_maps.cpp new file mode 100644 index 00000000000..c521fb28f72 --- /dev/null +++ b/test/Modules/modular_maps.cpp @@ -0,0 +1,6 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -I %S/Inputs/modular_maps %s -verify + +#include "a.h" +#include "b.h" // expected-error {{private header}} +const int val = a + b; // expected-error {{undeclared identifier}} -- GitLab