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 @@ -10968,6 +10968,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">; def err_module_partition_import_global : Error< @@ -11003,6 +11005,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 partitions 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 @@ -420,6 +420,20 @@ checkModuleImportContext(*this, Mod, ImportLoc, CurContext); + // C++20 + // 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 && !ModuleScopes.empty() && + ModuleScopes.back().Module->isModulePurview() && + ModuleScopes.back().Module == Mod) { + Diag(ImportLoc, diag::err_module_self_import_cxx20) + << Mod->getFullModuleName() + << !ModuleScopes.back().ModuleInterface; + } + // FIXME: we should support importing a submodule within a different submodule // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. @@ -471,7 +485,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, NamePath.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. @@ -483,7 +502,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,