diff options
Diffstat (limited to 'clang/lib/Sema/SemaModule.cpp')
-rw-r--r-- | clang/lib/Sema/SemaModule.cpp | 57 |
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. |