From 18057cb34c83a11889e0cced9ab43aa57875634f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 11 Oct 2017 00:36:56 +0000 Subject: [PATCH] [Modules TS] Diagnose missing/duplicate module-declaration. llvm-svn: 315397 --- .../include/clang/Basic/DiagnosticSemaKinds.td | 5 +++++ clang/lib/Sema/Sema.cpp | 11 +++++++++++ clang/lib/Sema/SemaDecl.cpp | 18 +++++++++++++----- .../dcl.module/dcl.module.interface/p1.cpp | 2 +- .../CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp | 14 ++++++++++++++ 5 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 clang/test/CXX/modules-ts/dcl.dcl/dcl.module/p1.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c26da79777d7..7f20be91df87 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 62692519674c..548f336c3b4c 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 84cae84dec7b..c2d480c34ff2 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 0ec1a90e1a08..68f2570dd3e6 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 000000000000..2393aa184317 --- /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