aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaModule.cpp
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2022-11-03 08:27:56 -0400
committerAaron Ballman <aaron@aaronballman.com>2022-11-03 08:29:59 -0400
commitb8ceb9f4e4bdb69b5c3ea1ccf8505fa244ca0a1e (patch)
tree2f20f2a96b615a47fb8ba05d38dce44ab399340c /clang/lib/Sema/SemaModule.cpp
parent3ee1882299f9f7d62c10093fa968f0b16669df0c (diff)
downloadllvm-b8ceb9f4e4bdb69b5c3ea1ccf8505fa244ca0a1e.zip
llvm-b8ceb9f4e4bdb69b5c3ea1ccf8505fa244ca0a1e.tar.gz
llvm-b8ceb9f4e4bdb69b5c3ea1ccf8505fa244ca0a1e.tar.bz2
[C++20] Diagnose invalid and reserved module names
[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. Differential Revision: https://reviews.llvm.org/D136953
Diffstat (limited to 'clang/lib/Sema/SemaModule.cpp')
-rw-r--r--clang/lib/Sema/SemaModule.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 4b01f10..19e2c20 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -144,6 +144,37 @@ void Sema::HandleStartOfHeaderUnit() {
TU->setLocalOwningModule(Mod);
}
+/// Tests whether the given identifier is reserved as a module name and
+/// diagnoses if it is. Returns true if a diagnostic is emitted and false
+/// otherwise.
+static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II,
+ SourceLocation Loc) {
+ enum {
+ Valid = -1,
+ Invalid = 0,
+ Reserved = 1,
+ } Reason = Valid;
+
+ StringRef PartName = II->getName();
+ if (II->isStr("module") || II->isStr("import"))
+ Reason = Invalid;
+ else if (II->isReserved(S.getLangOpts()) !=
+ ReservedIdentifierStatus::NotReserved)
+ Reason = Reserved;
+
+ // If the identifier is reserved (not invalid) but is in a system header,
+ // we do not diagnose (because we expect system headers to use reserved
+ // identifiers).
+ if (Reason == Reserved && S.getSourceManager().isInSystemHeader(Loc))
+ Reason = Valid;
+
+ if (Reason != Valid) {
+ S.Diag(Loc, diag::err_invalid_module_name) << II << (int)Reason;
+ return true;
+ }
+ return false;
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
ModuleDeclKind MDK, ModuleIdPath Path,
@@ -238,6 +269,32 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
}
}
+ // 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.
+
+ // Test the first part of the path to see if it's std[0-9]+ but allow the
+ // name in a system header.
+ StringRef FirstComponentName = Path[0].first->getName();
+ if (!getSourceManager().isInSystemHeader(Path[0].second) &&
+ (FirstComponentName == "std" ||
+ (FirstComponentName.startswith("std") &&
+ llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit)))) {
+ Diag(Path[0].second, diag::err_invalid_module_name)
+ << Path[0].first << /*reserved*/ 1;
+ return nullptr;
+ }
+
+ // Then test all of the components in the path to see if any of them are
+ // using another kind of reserved or invalid identifier.
+ for (auto Part : Path) {
+ if (DiagReservedModuleName(*this, Part.first, Part.second))
+ 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.