[C++20][Modules][5/8] Diagnose wrong import/export for partition CMIs.

We cannot export partition implementation CMIs, but we can export the content
of partition interface CMIs.

Differential Revision: https://reviews.llvm.org/D118588
This commit is contained in:
Iain Sandoe 2022-01-30 14:11:57 +00:00
parent 4d006520b8
commit 1a76d25639
5 changed files with 85 additions and 8 deletions

View File

@ -10991,6 +10991,8 @@ def ext_module_import_not_at_top_level_noop : ExtWarn<
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">;
@ -11024,6 +11026,8 @@ def err_export_using_internal : Error<
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<

View File

@ -403,10 +403,16 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
}
// 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 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// 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 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
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 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// [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);

View File

@ -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

View File

@ -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}}

View File

@ -118,13 +118,13 @@ import B; // expected-error {{module imports cannot be in the private module fra
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}}
//--- import-diags-tu10.cpp
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}}
//--- import-diags-tu11.cpp