iains created this revision. iains updated this revision to Diff 404484. iains added a comment. iains updated this revision to Diff 405594. iains updated this revision to Diff 405595. iains updated this revision to Diff 408763. iains updated this revision to Diff 408864. iains added reviewers: rsmith, urnathan, ChuanqiXu. iains published this revision for review. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Fix whitespace error. iains added a comment. rebased onto import state machine. iains added a comment. re-apply rebase iains added a comment. Rebased onto other modules work. iains added a comment. update formatting. iains added a comment. patch 5 of 8 to implement basic C++20 module partition support. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D118588 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaModule.cpp clang/test/Modules/cxx20-10-3-ex1.cpp clang/test/Modules/cxx20-10-3-ex2.cpp clang/test/Modules/cxx20-import-diagnostics-a.cpp
Index: clang/test/Modules/cxx20-import-diagnostics-a.cpp =================================================================== --- clang/test/Modules/cxx20-import-diagnostics-a.cpp +++ clang/test/Modules/cxx20-import-diagnostics-a.cpp @@ -25,12 +25,6 @@ // RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=7 -x c++ %s \ // RUN: -fmodule-file=%t/B.pcm -o %t/D.pcm -verify -// RUN: %clang_cc1 -std=c++20 -S -D TU=8 -x c++ %s \ -// RUN: -fmodule-file=%t/B.pcm -o %t/tu_8.s -verify - -// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=9 -x c++ %s \ -// RUN: -o %t/B.pcm -verify - // Test diagnostics for incorrect module import sequences. #if TU == 0 @@ -112,18 +106,6 @@ import B; // expected-error {{module imports cannot be in the private module fragment}} -#elif TU == 8 - -module B; - -import B; // expected-error {{import of module 'B' appears within same top-level module 'B'}} - -#elif TU == 9 - -export module B; - -import B; // expected-error {{import of module 'B' appears within same top-level module 'B'}} - #else #error "no MODE set" #endif Index: clang/test/Modules/cxx20-10-3-ex2.cpp =================================================================== --- /dev/null +++ clang/test/Modules/cxx20-10-3-ex2.cpp @@ -0,0 +1,28 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=0 -x c++ %s \ +// RUN: -o %t/M.pcm + +// RUN: %clang_cc1 -std=c++20 -S -D TU=1 -x c++ %s \ +// RUN: -fmodule-file=%t/M.pcm -o %t/tu_8.s -verify + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=2 -x c++ %s \ +// RUN: -o %t/M.pcm -verify + +#if TU == 0 +export module M; + +#elif TU == 1 +module M; + // error: cannot import M in its own unit +import M; // expected-error {{import of module 'M' appears within its own implementation}} + +#elif TU == 2 +export module M; + // error: cannot import M in its own unit +import M; // expected-error {{import of module 'M' appears within its own interface}} + +#else +#error "no TU set" +#endif Index: clang/test/Modules/cxx20-10-3-ex1.cpp =================================================================== --- /dev/null +++ clang/test/Modules/cxx20-10-3-ex1.cpp @@ -0,0 +1,36 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=1 -x c++ %s \ +// RUN: -o %t/M_PartImpl.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=2 -x c++ %s \ +// RUN: -fmodule-file=%t/M_PartImpl.pcm -o %t/M.pcm -verify + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=3 -x c++ %s \ +// RUN: -o %t/M_Part.pcm + +// RUN: %clang_cc1 -std=c++20 -emit-module-interface -D TU=4 -x c++ %s \ +// RUN: -fmodule-file=%t/M_Part.pcm -o %t/M.pcm + +#if TU == 1 +module M:PartImpl; + +// expected-no-diagnostics +#elif TU == 2 +export module M; + // error: exported partition :Part is an implementation unit +export import :PartImpl; // expected-error {{module partition implementations cannot be exported}} + +#elif TU == 3 +export module M:Part; + +// expected-no-diagnostics +#elif TU == 4 +export module M; +export import :Part; + +// expected-no-diagnostics +#else +#error "no TU set" +#endif Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -396,10 +396,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; } @@ -433,8 +439,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 @@ -475,7 +480,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. @@ -487,7 +497,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); Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ 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<
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits