summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/docs/Modules.rst4
-rw-r--r--clang/include/clang/Basic/DiagnosticLexKinds.td1
-rw-r--r--clang/lib/Lex/ModuleMap.cpp59
-rw-r--r--clang/test/Modules/Inputs/modular_maps/a.h4
-rw-r--r--clang/test/Modules/Inputs/modular_maps/b.h4
-rw-r--r--clang/test/Modules/Inputs/modular_maps/module.map6
-rw-r--r--clang/test/Modules/Inputs/modular_maps/moduleb.map3
-rw-r--r--clang/test/Modules/modular_maps.cpp6
8 files changed, 85 insertions, 2 deletions
diff --git a/clang/docs/Modules.rst b/clang/docs/Modules.rst
index c086644ee3f..8c20301315c 100644
--- a/clang/docs/Modules.rst
+++ b/clang/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/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 41ec81ca260..f1c8a09dee6 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/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/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index d411ead7e96..b2698b1877d 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/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/clang/test/Modules/Inputs/modular_maps/a.h b/clang/test/Modules/Inputs/modular_maps/a.h
new file mode 100644
index 00000000000..a36dc1b59d6
--- /dev/null
+++ b/clang/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/clang/test/Modules/Inputs/modular_maps/b.h b/clang/test/Modules/Inputs/modular_maps/b.h
new file mode 100644
index 00000000000..55daf728680
--- /dev/null
+++ b/clang/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/clang/test/Modules/Inputs/modular_maps/module.map b/clang/test/Modules/Inputs/modular_maps/module.map
new file mode 100644
index 00000000000..7018c413042
--- /dev/null
+++ b/clang/test/Modules/Inputs/modular_maps/module.map
@@ -0,0 +1,6 @@
+module A {
+ header "a.h"
+}
+
+extern module B "moduleb.map"
+
diff --git a/clang/test/Modules/Inputs/modular_maps/moduleb.map b/clang/test/Modules/Inputs/modular_maps/moduleb.map
new file mode 100644
index 00000000000..6f36ccd3baa
--- /dev/null
+++ b/clang/test/Modules/Inputs/modular_maps/moduleb.map
@@ -0,0 +1,3 @@
+module B {
+ private header "b.h"
+}
diff --git a/clang/test/Modules/modular_maps.cpp b/clang/test/Modules/modular_maps.cpp
new file mode 100644
index 00000000000..c521fb28f72
--- /dev/null
+++ b/clang/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}}
OpenPOWER on IntegriCloud