From 145e15a37b7df0fdd9f7221801336d7d8d2d46c7 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 24 Apr 2017 23:12:30 +0000 Subject: [PATCH] [modules ts] Diagnose 'export' declarations outside of a module interface. llvm-svn: 301271 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 +++++- clang/include/clang/Basic/Module.h | 12 ++++++++++ clang/lib/Lex/ModuleMap.cpp | 1 + clang/lib/Sema/SemaDecl.cpp | 6 +++++ clang/lib/Serialization/ASTReader.cpp | 3 +++ clang/lib/Serialization/ASTWriter.cpp | 7 +++--- .../dcl.dcl/dcl.module/dcl.module.interface/p1.cpp | 27 ++++++++++++++++++++++ clang/test/Parser/cxx-modules-interface.cppm | 3 +-- clang/test/SemaCXX/modules-ts.cppm | 13 +++++------ 9 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 914e304d..b5fed1f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8804,7 +8804,7 @@ let CategoryName = "Modules Issue" in { def err_module_decl_in_module_map_module : Error< "'module' declaration found while building module from module map">; def err_module_interface_implementation_mismatch : Error< - "missing 'export' specifier in 'module' declaration while " + "missing 'export' specifier in module declaration while " "building module interface">; def err_current_module_name_mismatch : Error< "module name '%0' specified on command line does not match name of module">; @@ -8848,8 +8848,13 @@ def err_module_self_import : Error< "import of module '%0' appears within same top-level module '%1'">; def err_module_import_in_implementation : Error< "@import of module '%0' in implementation of '%1'; use #import">; + +// C++ Modules TS def err_export_within_export : Error< "export declaration appears within another export declaration">; +def err_export_not_in_module_interface : Error< + "export declaration can only be used within a module interface unit after " + "the module declaration">; def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn< "ambiguous use of internal linkage declaration %0 defined in multiple modules">, diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index 8fcb0e8..28aa7db 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -62,6 +62,18 @@ public: /// \brief The location of the module definition. SourceLocation DefinitionLoc; + enum ModuleKind { + /// \brief This is a module that was defined by a module map and built out + /// of header files. + ModuleMapModule, + + /// \brief This is a C++ Modules TS module interface unit. + ModuleInterfaceUnit + }; + + /// \brief The kind of this module. + ModuleKind Kind = ModuleMapModule; + /// \brief The parent of this module. This will be NULL for the top-level /// module. Module *Parent; diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 5b60ed3..512d7dc 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -581,6 +581,7 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, auto *Result = new Module(Name, Loc, nullptr, /*IsFramework*/ false, /*IsExplicit*/ false, NumCreatedModules++); + Result->Kind = Module::ModuleInterfaceUnit; Modules[Name] = SourceModule = Result; // Mark the main source file as being within the newly-created module so that diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6138cbb..e7ea68e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15922,6 +15922,12 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc); // C++ Modules TS draft: + // An export-declaration shall appear in the purview of a module other than + // the global module. + if (ModuleScopes.empty() || !ModuleScopes.back().Module || + ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit) + Diag(ExportLoc, diag::err_export_not_in_module_interface); + // An export-declaration [...] shall not contain more than one // export keyword. // diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 406c4b5..7b1edc0 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4779,6 +4779,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; Module *CurrentModule = nullptr; + Module::ModuleKind ModuleKind = Module::ModuleMapModule; RecordData Record; while (true) { llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks(); @@ -4871,6 +4872,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { CurrentModule->setASTFile(F.File); } + CurrentModule->Kind = ModuleKind; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; @@ -4969,6 +4971,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); } + ModuleKind = (Module::ModuleKind)Record[2]; break; } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index bb86907..5758ac9 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -2694,9 +2694,10 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); // Write the submodule metadata block. - RecordData::value_type Record[] = {getNumberOfModules(WritingModule), - FirstSubmoduleID - - NUM_PREDEF_SUBMODULE_IDS}; + RecordData::value_type Record[] = { + getNumberOfModules(WritingModule), + FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS, + WritingModule->Kind}; Stream.EmitRecord(SUBMODULE_METADATA, Record); // Write all of the submodules. 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 new file mode 100644 index 0000000..afe3a7a --- /dev/null +++ b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -fmodules-ts %s -verify -o /dev/null +// RUN: %clang_cc1 -fmodules-ts %s -DINTERFACE -verify -o /dev/null +// RUN: %clang_cc1 -fmodules-ts %s -DIMPLEMENTATION -verify -o /dev/null +// +// RUN: %clang_cc1 -fmodules-ts %s -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null +// RUN: %clang_cc1 -fmodules-ts %s -DINTERFACE -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null +// RUN: %clang_cc1 -fmodules-ts %s -DIMPLEMENTATION -DBUILT_AS_INTERFACE -emit-module-interface -verify -o /dev/null + +#if INTERFACE +export module A; +#elif IMPLEMENTATION +module A; + #ifdef BUILT_AS_INTERFACE + // expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}} + #endif +#else + #ifdef BUILT_AS_INTERFACE + // FIXME: Diagnose missing module declaration (at end of TU) + #endif +#endif + +export int a; +#ifndef INTERFACE +// expected-error@-2 {{export declaration can only be used within a module interface unit}} +#else +// expected-no-diagnostics +#endif diff --git a/clang/test/Parser/cxx-modules-interface.cppm b/clang/test/Parser/cxx-modules-interface.cppm index 628b854..0e7c746 100644 --- a/clang/test/Parser/cxx-modules-interface.cppm +++ b/clang/test/Parser/cxx-modules-interface.cppm @@ -1,11 +1,10 @@ // RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DERRORS +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DERRORS export module foo; #ifndef ERRORS // expected-no-diagnostics #else -// FIXME: diagnose 'export' declaration in non-module // FIXME: diagnose missing module-declaration when building module interface // FIXME: proclaimed-ownership-declarations? diff --git a/clang/test/SemaCXX/modules-ts.cppm b/clang/test/SemaCXX/modules-ts.cppm index 109a1f4..16695f6 100644 --- a/clang/test/SemaCXX/modules-ts.cppm +++ b/clang/test/SemaCXX/modules-ts.cppm @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=0 -// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -Dmodule=int -DTEST=1 -// RUN: not %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -DTEST=2 2>&1 | FileCheck %s --check-prefix=CHECK-2 +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t.pcm -verify -DTEST=1 +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -DTEST=2 // RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -fmodule-file=%t.pcm -o %t.pcm -verify -Dfoo=bar -DTEST=3 #if TEST == 0 @@ -8,15 +8,14 @@ #endif export module foo; -#if TEST == 1 -// FIXME: diagnose export outside of module interface unit -#elif TEST == 2 -// CHECK-2: error: redefinition of module 'foo' +#if TEST == 2 +// expected-error@-2 {{redefinition of module 'foo'}} +// expected-note@modules-ts.cppm:* {{loaded from}} #endif static int m; // ok, internal linkage, so no redefinition error int n; -#if TEST == 3 +#if TEST >= 2 // expected-error@-2 {{redefinition of '}} // expected-note@-3 {{previous}} #endif -- 2.7.4