[modules ts] Diagnose 'export' declarations outside of a module interface.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 24 Apr 2017 23:12:30 +0000 (23:12 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 24 Apr 2017 23:12:30 +0000 (23:12 +0000)
llvm-svn: 301271

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/Module.h
clang/lib/Lex/ModuleMap.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.interface/p1.cpp [new file with mode: 0644]
clang/test/Parser/cxx-modules-interface.cppm
clang/test/SemaCXX/modules-ts.cppm

index 914e304..b5fed1f 100644 (file)
@@ -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">,
index 8fcb0e8..28aa7db 100644 (file)
@@ -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;
index 5b60ed3..512d7dc 100644 (file)
@@ -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
index 6138cbb..e7ea68e 100644 (file)
@@ -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.
   //
index 406c4b5..7b1edc0 100644 (file)
@@ -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;
     }
 
index bb86907..5758ac9 100644 (file)
@@ -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 (file)
index 0000000..afe3a7a
--- /dev/null
@@ -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
index 628b854..0e7c746 100644 (file)
@@ -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?
index 109a1f4..16695f6 100644 (file)
@@ -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