Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11205,6 +11205,8 @@ "private module fragment in module implementation unit">; def note_not_module_interface_add_export : Note< "add 'export' here if this is intended to be a module interface unit">; +def err_invalid_module_name : Error< + "%0 is %select{an invalid|a reserved}1 name for a module">; def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn< "ambiguous use of internal linkage declaration %0 defined in multiple modules">, Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -238,6 +238,33 @@ } } + // C++2b [module.unit]p1: ... The identifiers module and import shall not + // appear as identifiers in a module-name or module-partition. All + // module-names either beginning with an identifier consisting of std + // followed by zero or more digits or containing a reserved identifier + // ([lex.name]) are reserved and shall not be specified in a + // module-declaration; no diagnostic is required. + for (auto Part : Path) { + int Reason = -1; + const IdentifierInfo *II = Part.first; + StringRef PartName = II->getName(); + if (II->isStr("module") || II->isStr("import")) + Reason = /*invalid*/ 0; + else if (II->isReserved(getLangOpts()) != + ReservedIdentifierStatus::NotReserved) + Reason = /*reserved*/ 1; + else if (PartName.startswith("std") && + (PartName.size() == 3 || isDigit(PartName.drop_front(3)[0]))) + Reason = /*reserved*/ 1; + + // If the identifier is reserved but is in a system header, we do not + // diagnose (because we expect system headers to use reserved identifiers). + if (Reason != -1 && !getSourceManager().isInSystemHeader(Part.second)) { + Diag(Part.second, diag::err_invalid_module_name) << Part.first << Reason; + return nullptr; + } + } + // Flatten the dots in a module name. Unlike Clang's hierarchical module map // modules, the dots here are just another character that can appear in a // module name. Index: clang/test/Modules/reserved-names.cpp =================================================================== --- /dev/null +++ clang/test/Modules/reserved-names.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +// expected-note@1 14{{add 'module;' to the start of the file to introduce a global module fragment}} + +module std; // expected-error {{'std' is a reserved name for a module}} +module _Test; // expected-error {{'_Test' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +module module; // expected-error {{'module' is an invalid name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +module std0; // expected-error {{'std0' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} + +export module module; // expected-error {{'module' is an invalid name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module import; // expected-error {{'import' is an invalid name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module _Test; // expected-error {{'_Test' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module __test; // expected-error {{'__test' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module te__st; // expected-error {{'te__st' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module std; // expected-error {{'std' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module std0; // expected-error {{'std0' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module std1000000; // expected-error {{'std1000000' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} + +export module should_fail.std0; // expected-error {{'std0' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} +export module should_fail._Test; // expected-error {{'_Test' is a reserved name for a module}} \ + expected-error {{module declaration must occur at the start of the translation unit}} + +// Show that we suppress the diagnostic in a system header. +# 100 "file.cpp" 1 3 // Enter a system header +export module std; // expected-error {{module declaration must occur at the start of the translation unit}} +# 100 "file.cpp" 2 3 // Leave the system header