summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--clang/lib/Sema/Sema.cpp11
-rw-r--r--clang/lib/Sema/SemaDecl.cpp18
-rw-r--r--clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp2
-rw-r--r--clang/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp14
5 files changed, 44 insertions, 6 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c26da79777d..7f20be91df8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8997,6 +8997,11 @@ def note_prev_module_definition_from_ast_file : Note<"module loaded from '%0'">;
def err_module_not_defined : Error<
"definition of module '%0' is not available; use -fmodule-file= to specify "
"path to precompiled module interface">;
+def err_module_redeclaration : Error<
+ "translation unit contains multiple module declarations">;
+def note_prev_module_declaration : Note<"previous module declaration is here">;
+def err_module_declaration_missing : Error<
+ "missing 'export module' declaration in module interface unit">;
def err_module_private_specialization : Error<
"%select{template|partial|member}0 specialization cannot be "
"declared __module_private__">;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 62692519674..548f336c3b4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -930,6 +930,17 @@ void Sema::ActOnEndOfTranslationUnit() {
}
if (TUKind == TU_Module) {
+ // If we are building a module interface unit, we need to have seen the
+ // module declaration by now.
+ if (getLangOpts().getCompilingModule() ==
+ LangOptions::CMK_ModuleInterface &&
+ ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) {
+ // FIXME: Make a better guess as to where to put the module declaration.
+ Diag(getSourceManager().getLocForStartOfFile(
+ getSourceManager().getMainFileID()),
+ diag::err_module_declaration_missing);
+ }
+
// If we are building a module, resolve all of the exported declarations
// now.
if (Module *CurrentModule = PP.getCurrentModule()) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 84cae84dec7..c2d480c34ff 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16176,9 +16176,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
return nullptr;
}
+ assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
+
// FIXME: Most of this work should be done by the preprocessor rather than
// here, in order to support macro import.
+ // Only one module-declaration is permitted per source file.
+ if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
+ Diag(ModuleLoc, diag::err_module_redeclaration);
+ Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
+ diag::note_prev_module_declaration);
+ return nullptr;
+ }
+
// Flatten the dots in a module name. Unlike Clang's hierarchical module map
// modules, the dots here are just another character that can appear in a
// module name.
@@ -16189,8 +16199,6 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
ModuleName += Piece.first->getName();
}
- // FIXME: If we've already seen a module-declaration, report an error.
-
// If a module name was explicitly specified on the command line, it must be
// correct.
if (!getLangOpts().CurrentModule.empty() &&
@@ -16205,8 +16213,6 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
Module *Mod;
- assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
-
switch (MDK) {
case ModuleDeclKind::Interface: {
// We can't have parsed or imported a definition of this module or parsed a
@@ -16240,7 +16246,9 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
/*IsIncludeDirective=*/false);
if (!Mod) {
Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
- return nullptr;
+ // Create an empty module interface unit for error recovery.
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ ModuleScopes.front().Module);
}
break;
}
diff --git a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp
index 0ec1a90e1a0..68f2570dd3e 100644
--- a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp
+++ b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp
@@ -17,7 +17,7 @@ module A;
#endif
#else
#ifdef BUILT_AS_INTERFACE
- // FIXME: Diagnose missing module declaration (at end of TU)
+ // expected-error@1 {{missing 'export module' declaration in module interface unit}}
#endif
#endif
diff --git a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp
new file mode 100644
index 00000000000..2393aa18431
--- /dev/null
+++ b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts -verify %s -DFOO=export -DBAR=export
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts -verify %s -DFOO=export -DBAR=
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s -DFOO=export -emit-module-interface -o %t
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s -fmodule-file=%t -DFOO=
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s -fmodule-file=%t -DBAR=export
+// RUN: %clang_cc1 -std=c++17 -fmodules-ts -verify %s -fmodule-file=%t -DFOO= -DBAR=export
+
+#ifdef FOO
+FOO module foo; // expected-note {{previous module declaration is here}}
+#endif
+
+#ifdef BAR
+BAR module bar; // expected-error {{translation unit contains multiple module declarations}}
+#endif
OpenPOWER on IntegriCloud