[PATCH] D136953: [C++20] Diagnosed invalid and reserved module names

Aaron Ballman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 28 07:52:49 PDT 2022


aaron.ballman created this revision.
aaron.ballman added reviewers: iains, urnathan, ChuanqiXu, clang-language-wg.
Herald added a project: All.
aaron.ballman requested review of this revision.
Herald added a project: clang.

[module.unit]p1 specifies that `module` and `import` are invalid components of a module name, that module names cannot contain reserved identifiers, and that `std` followed by zero or more digits is reserved.

The first issue (`module` and `import` pseudo-keywords) requires a diagnostic, the second issue (use of reserved identifiers) does not require a diagnostic. We diagnose both the same -- the code is ill-formed unless the module declaration is in a system header. This allows STL implementations to use the reserved module names while preventing users from stealing them out from under us.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136953

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaModule.cpp
  clang/test/Modules/reserved-names.cpp


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 at 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
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/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">,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D136953.471550.patch
Type: text/x-patch
Size: 5640 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20221028/891e81c3/attachment-0001.bin>


More information about the cfe-commits mailing list