diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10988,6 +10988,8 @@ def note_module_import_not_at_top_level : Note<"%0 begins here">; def err_module_self_import : Error< "import of module '%0' appears within same top-level module '%1'">; +def err_module_self_import_cxx20 : Error< + "import of module '%0' appears within its own %select{interface|implementation}1">; def err_module_import_in_implementation : Error< "@import of module '%0' in implementation of '%1'; use #import">; @@ -11021,6 +11023,8 @@ def err_export_not_in_module_interface : Error< "export declaration can only be used within a module interface unit" "%select{ after the module declaration|}0">; +def err_export_partition_impl : Error< + "module partition implementations cannot be exported">; def err_export_in_private_module_fragment : Error< "export declaration cannot be used in a private module fragment">; def note_private_module_fragment : Note< diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -403,10 +403,16 @@ } // Diagnose self-import before attempting a load. + // [module.import]/9 + // A module implementation unit of a module M that is not a module partition + // shall not contain a module-import-declaration nominating M. + // (for an implementation, the module interface is imported implicitly, + // but that's handled in the module decl code). + if (getLangOpts().CPlusPlusModules && isCurrentModulePurview() && getCurrentModule()->Name == ModuleName) { - Diag(ImportLoc, diag::err_module_self_import) - << ModuleName << getLangOpts().CurrentModule; + Diag(ImportLoc, diag::err_module_self_import_cxx20) + << ModuleName << !ModuleScopes.back().ModuleInterface; return true; } @@ -440,8 +446,7 @@ // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. // FIXME: Should we warn on a redundant import of the current module? - if (!getLangOpts().CPlusPlusModules && - Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && + if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) { Diag(ImportLoc, getLangOpts().isCompilingModule() ? diag::err_module_self_import @@ -482,7 +487,12 @@ if (!ModuleScopes.empty()) Context.addModuleInitializer(ModuleScopes.back().Module, Import); - if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) { + // A module (partition) implementation unit shall not be exported. + if (getLangOpts().CPlusPlusModules && Mod && ExportLoc.isValid() && + Mod->Kind == Module::ModuleKind::ModulePartitionImplementation) { + Diag(ExportLoc, diag::err_export_partition_impl) + << SourceRange(ExportLoc, Path.back().second); + } else if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) { // Re-export the module if the imported module is exported. // Note that we don't need to add re-exported module to Imports field // since `Exports` implies the module is imported already. @@ -494,7 +504,9 @@ // [module.interface]p1: // An export-declaration shall inhabit a namespace scope and appear in the // purview of a module interface unit. - Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; + Diag(ExportLoc, diag::err_export_not_in_module_interface) + << (!ModuleScopes.empty() && + !ModuleScopes.back().ImplicitGlobalModuleFragment); } else if (getLangOpts().isCompilingModule()) { Module *ThisModule = PP.getHeaderSearchInfo().lookupModule( getLangOpts().CurrentModule, ExportLoc, false, false); diff --git a/clang/test/Modules/cxx20-10-3-ex1.cpp b/clang/test/Modules/cxx20-10-3-ex1.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Modules/cxx20-10-3-ex1.cpp @@ -0,0 +1,36 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-3-ex1-tu1.cpp \ +// RUN: -o %t/M_PartImpl.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-3-ex1-tu2.cpp \ +// RUN: -fmodule-file=%t/M_PartImpl.pcm -o %t/M.pcm -verify + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-3-ex1-tu3.cpp \ +// RUN: -o %t/M_Part.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-3-ex1-tu4.cpp \ +// RUN: -fmodule-file=%t/M_Part.pcm -o %t/M.pcm + +//--- std10-3-ex1-tu1.cpp +module M:PartImpl; + +// expected-no-diagnostics + +//--- std10-3-ex1-tu2.cpp +export module M; + // error: exported partition :Part is an implementation unit +export import :PartImpl; // expected-error {{module partition implementations cannot be exported}} + +//--- std10-3-ex1-tu3.cpp +export module M:Part; + +// expected-no-diagnostics + +//--- std10-3-ex1-tu4.cpp +export module M; +export import :Part; + +// expected-no-diagnostics diff --git a/clang/test/Modules/cxx20-10-3-ex2.cpp b/clang/test/Modules/cxx20-10-3-ex2.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Modules/cxx20-10-3-ex2.cpp @@ -0,0 +1,25 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-3-ex2-tu1.cpp \ +// RUN: -o %t/M.pcm + +// RUN: %clang_cc1 -std=c++20 -S %t/std10-3-ex2-tu2.cpp \ +// RUN: -fmodule-file=%t/M.pcm -o %t/tu_8.s -verify + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-3-ex2-tu3.cpp \ +// RUN: -o %t/M.pcm -verify + +//--- std10-3-ex2-tu1.cpp +export module M; + +//--- std10-3-ex2-tu2.cpp +module M; + // error: cannot import M in its own unit +import M; // expected-error {{import of module 'M' appears within its own implementation}} + +//--- std10-3-ex2-tu3.cpp +export module M; + // error: cannot import M in its own unit +import M; // expected-error {{import of module 'M' appears within its own interface}} diff --git a/clang/test/Modules/cxx20-import-diagnostics-a.cpp b/clang/test/Modules/cxx20-import-diagnostics-a.cpp --- a/clang/test/Modules/cxx20-import-diagnostics-a.cpp +++ b/clang/test/Modules/cxx20-import-diagnostics-a.cpp @@ -117,13 +117,13 @@ module B; -import B; // expected-error {{import of module 'B' appears within same top-level module 'B'}} +import B; // expected-error {{import of module 'B' appears within its own implementation}} #elif TU == 9 export module B; -import B; // expected-error {{import of module 'B' appears within same top-level module 'B'}} +import B; // expected-error {{import of module 'B' appears within its own interface}} #elif TU == 10