diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/Lex/ModuleMap.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 192 |
1 files changed, 113 insertions, 79 deletions
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 47d6f5893e97..ee2cca4e0814 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -28,7 +28,6 @@ #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Token.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" @@ -47,6 +46,7 @@ #include <cassert> #include <cstdint> #include <cstring> +#include <optional> #include <string> #include <system_error> #include <utility> @@ -75,7 +75,6 @@ void ModuleMap::addLinkAsDependency(Module *Mod) { Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) { switch ((int)Role) { - default: llvm_unreachable("unknown header role"); case NormalHeader: return Module::HK_Normal; case PrivateHeader: @@ -84,7 +83,10 @@ Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) { return Module::HK_Textual; case PrivateHeader | TextualHeader: return Module::HK_PrivateTextual; + case ExcludedHeader: + return Module::HK_Excluded; } + llvm_unreachable("unknown header role"); } ModuleMap::ModuleHeaderRole @@ -99,11 +101,15 @@ ModuleMap::headerKindToRole(Module::HeaderKind Kind) { case Module::HK_PrivateTextual: return ModuleHeaderRole(PrivateHeader | TextualHeader); case Module::HK_Excluded: - llvm_unreachable("unexpected header kind"); + return ExcludedHeader; } llvm_unreachable("unknown header kind"); } +bool ModuleMap::isModular(ModuleHeaderRole Role) { + return !(Role & (ModuleMap::TextualHeader | ModuleMap::ExcludedHeader)); +} + Module::ExportDecl ModuleMap::resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved, @@ -171,23 +177,23 @@ static void appendSubframeworkPaths(Module *Mod, llvm::sys::path::append(Path, "Frameworks", Framework + ".framework"); } -Optional<FileEntryRef> ModuleMap::findHeader( +OptionalFileEntryRef ModuleMap::findHeader( Module *M, const Module::UnresolvedHeaderDirective &Header, SmallVectorImpl<char> &RelativePathName, bool &NeedsFramework) { // Search for the header file within the module's home directory. auto *Directory = M->Directory; SmallString<128> FullPathName(Directory->getName()); - auto GetFile = [&](StringRef Filename) -> Optional<FileEntryRef> { + auto GetFile = [&](StringRef Filename) -> OptionalFileEntryRef { auto File = expectedToOptional(SourceMgr.getFileManager().getFileRef(Filename)); if (!File || (Header.Size && File->getSize() != *Header.Size) || (Header.ModTime && File->getModificationTime() != *Header.ModTime)) - return None; + return std::nullopt; return *File; }; - auto GetFrameworkFile = [&]() -> Optional<FileEntryRef> { + auto GetFrameworkFile = [&]() -> OptionalFileEntryRef { unsigned FullPathLength = FullPathName.size(); appendSubframeworkPaths(M, RelativePathName); unsigned RelativePathLength = RelativePathName.size(); @@ -241,7 +247,7 @@ Optional<FileEntryRef> ModuleMap::findHeader( << Header.FileName << M->getFullModuleName(); NeedsFramework = true; } - return None; + return std::nullopt; } return NormalHdrFile; @@ -251,7 +257,7 @@ void ModuleMap::resolveHeader(Module *Mod, const Module::UnresolvedHeaderDirective &Header, bool &NeedsFramework) { SmallString<128> RelativePathName; - if (Optional<FileEntryRef> File = + if (OptionalFileEntryRef File = findHeader(Mod, Header, RelativePathName, NeedsFramework)) { if (Header.IsUmbrella) { const DirectoryEntry *UmbrellaDir = &File->getDir().getDirEntry(); @@ -264,10 +270,7 @@ void ModuleMap::resolveHeader(Module *Mod, } else { Module::Header H = {Header.FileName, std::string(RelativePathName.str()), *File}; - if (Header.Kind == Module::HK_Excluded) - excludeHeader(Mod, H); - else - addHeader(Mod, H, headerKindToRole(Header.Kind)); + addHeader(Mod, H, headerKindToRole(Header.Kind)); } } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) { // There's a builtin header but no corresponding on-disk header. Assume @@ -301,7 +304,7 @@ bool ModuleMap::resolveAsBuiltinHeader( // supplied by Clang. Find that builtin header. SmallString<128> Path; llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName); - auto File = SourceMgr.getFileManager().getFile(Path); + auto File = SourceMgr.getFileManager().getOptionalFileRef(Path); if (!File) return false; @@ -479,7 +482,7 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule, if (RequestingModule) { resolveUses(RequestingModule, /*Complain=*/false); - resolveHeaderDirectives(RequestingModule, /*File=*/llvm::None); + resolveHeaderDirectives(RequestingModule, /*File=*/std::nullopt); } bool Excluded = false; @@ -489,6 +492,12 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule, HeadersMap::iterator Known = findKnownHeader(File); if (Known != Headers.end()) { for (const KnownHeader &Header : Known->second) { + // Excluded headers don't really belong to a module. + if (Header.getRole() == ModuleMap::ExcludedHeader) { + Excluded = true; + continue; + } + // Remember private headers for later printing of a diagnostic. if (violatesPrivateInclude(RequestingModule, File, Header)) { Private = Header.getModule(); @@ -562,12 +571,18 @@ static bool isBetterKnownHeader(const ModuleMap::KnownHeader &New, (Old.getRole() & ModuleMap::TextualHeader)) return !(New.getRole() & ModuleMap::TextualHeader); + // Prefer a non-excluded header over an excluded header. + if ((New.getRole() == ModuleMap::ExcludedHeader) != + (Old.getRole() == ModuleMap::ExcludedHeader)) + return New.getRole() != ModuleMap::ExcludedHeader; + // Don't have a reason to choose between these. Just keep the first one. return false; } ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File, - bool AllowTextual) { + bool AllowTextual, + bool AllowExcluded) { auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader { if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader) return {}; @@ -579,6 +594,9 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File, ModuleMap::KnownHeader Result; // Iterate over all modules that 'File' is part of to find the best fit. for (KnownHeader &H : Known->second) { + // Cannot use a module if the header is excluded in it. + if (!AllowExcluded && H.getRole() == ModuleMap::ExcludedHeader) + continue; // Prefer a header from the source module over all others. if (H.getModule()->getTopLevelModule() == SourceModule) return MakeResult(H); @@ -607,7 +625,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) { UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - const FileEntry *UmbrellaModuleMap = + OptionalFileEntryRefDegradesToFileEntryPtr UmbrellaModuleMap = getModuleMapFileForUniquing(UmbrellaModule); // Infer submodules for each of the directories we found between @@ -672,7 +690,7 @@ ModuleMap::findAllModulesForHeader(const FileEntry *File) { if (findOrCreateModuleForHeaderInUmbrellaDir(File)) return Headers.find(File)->second; - return None; + return std::nullopt; } ArrayRef<ModuleMap::KnownHeader> @@ -681,7 +699,7 @@ ModuleMap::findResolvedModulesForHeader(const FileEntry *File) const { resolveHeaderDirectives(File); auto It = Headers.find(File); if (It == Headers.end()) - return None; + return std::nullopt; return It->second; } @@ -700,6 +718,9 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header, E = Known->second.end(); I != E; ++I) { + if (I->getRole() == ModuleMap::ExcludedHeader) + continue; + if (I->isAvailable() && (!RequestingModule || I->getModule()->isSubModuleOf(RequestingModule))) { @@ -852,8 +873,7 @@ ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent, } Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, - StringRef Name, - Module *GlobalModule) { + StringRef Name) { assert(LangOpts.CurrentModule == Name && "module name mismatch"); assert(!Modules[Name] && "redefining existing module"); @@ -879,29 +899,6 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc, return Result; } -Module *ModuleMap::createHeaderModule(StringRef Name, - ArrayRef<Module::Header> Headers) { - assert(LangOpts.CurrentModule == Name && "module name mismatch"); - assert(!Modules[Name] && "redefining existing module"); - - auto *Result = - new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false, - /*IsExplicit*/ false, NumCreatedModules++); - Result->Kind = Module::ModuleInterfaceUnit; - Modules[Name] = SourceModule = Result; - - for (const Module::Header &H : Headers) { - auto *M = new Module(H.NameAsWritten, SourceLocation(), Result, - /*IsFramework*/ false, - /*IsExplicit*/ true, NumCreatedModules++); - // Header modules are implicitly 'export *'. - M->Exports.push_back(Module::ExportDecl(nullptr, true)); - addHeader(M, H, NormalHeader); - } - - return Result; -} - Module *ModuleMap::createHeaderUnit(SourceLocation Loc, StringRef Name, Module::Header H) { assert(LangOpts.CurrentModule == Name && "module name mismatch"); @@ -1018,14 +1015,16 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir, // If we're not allowed to infer a framework module, don't. if (!canInfer) return nullptr; - } else - ModuleMapFile = getModuleMapFileForUniquing(Parent); - + } else { + OptionalFileEntryRefDegradesToFileEntryPtr ModuleMapRef = + getModuleMapFileForUniquing(Parent); + ModuleMapFile = ModuleMapRef; + } // Look for an umbrella header. SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h"); - auto UmbrellaHeader = FileMgr.getFile(UmbrellaName); + auto UmbrellaHeader = FileMgr.getOptionalFileRef(UmbrellaName); // FIXME: If there's no umbrella header, we could probably scan the // framework to load *everything*. But, it's not clear that this is a good @@ -1137,14 +1136,14 @@ Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework, } void ModuleMap::setUmbrellaHeader( - Module *Mod, const FileEntry *UmbrellaHeader, const Twine &NameAsWritten, + Module *Mod, FileEntryRef UmbrellaHeader, const Twine &NameAsWritten, const Twine &PathRelativeToRootModuleDirectory) { Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader)); - Mod->Umbrella = UmbrellaHeader; + Mod->Umbrella = &UmbrellaHeader.getMapEntry(); Mod->UmbrellaAsWritten = NameAsWritten.str(); Mod->UmbrellaRelativeToRootModuleDirectory = PathRelativeToRootModuleDirectory.str(); - UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; + UmbrellaDirs[UmbrellaHeader.getDir()] = Mod; // Notify callbacks that we just added a new header. for (const auto &Cb : Callbacks) @@ -1214,11 +1213,11 @@ void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const { } void ModuleMap::resolveHeaderDirectives( - Module *Mod, llvm::Optional<const FileEntry *> File) const { + Module *Mod, std::optional<const FileEntry *> File) const { bool NeedsFramework = false; SmallVector<Module::UnresolvedHeaderDirective, 1> NewHeaders; - const auto Size = File ? File.value()->getSize() : 0; - const auto ModTime = File ? File.value()->getModificationTime() : 0; + const auto Size = File ? (*File)->getSize() : 0; + const auto ModTime = File ? (*File)->getModificationTime() : 0; for (auto &Header : Mod->UnresolvedHeaders) { if (File && ((Header.ModTime && Header.ModTime != ModTime) || @@ -1260,29 +1259,21 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header, Cb->moduleMapAddHeader(Header.Entry->getName()); } -void ModuleMap::excludeHeader(Module *Mod, Module::Header Header) { - // Add this as a known header so we won't implicitly add it to any - // umbrella directory module. - // FIXME: Should we only exclude it from umbrella modules within the - // specified module? - (void) Headers[Header.Entry]; - - Mod->Headers[Module::HK_Excluded].push_back(std::move(Header)); -} - -const FileEntry * +OptionalFileEntryRef ModuleMap::getContainingModuleMapFile(const Module *Module) const { if (Module->DefinitionLoc.isInvalid()) - return nullptr; + return std::nullopt; - return SourceMgr.getFileEntryForID( - SourceMgr.getFileID(Module->DefinitionLoc)); + return SourceMgr.getFileEntryRefForID( + SourceMgr.getFileID(Module->DefinitionLoc)); } -const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const { +OptionalFileEntryRef +ModuleMap::getModuleMapFileForUniquing(const Module *M) const { if (M->IsInferred) { assert(InferredModuleAllowedBy.count(M) && "missing inferred module map"); - return InferredModuleAllowedBy.find(M)->second; + // FIXME: Update InferredModuleAllowedBy to use FileEntryRef. + return InferredModuleAllowedBy.find(M)->second->getLastRef(); } return getContainingModuleMapFile(M); } @@ -1292,6 +1283,49 @@ void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) { InferredModuleAllowedBy[M] = ModMap; } +std::error_code +ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl<char> &Path) { + StringRef Dir = llvm::sys::path::parent_path({Path.data(), Path.size()}); + + // Do not canonicalize within the framework; the module map parser expects + // Modules/ not Versions/A/Modules. + if (llvm::sys::path::filename(Dir) == "Modules") { + StringRef Parent = llvm::sys::path::parent_path(Dir); + if (Parent.endswith(".framework")) + Dir = Parent; + } + + FileManager &FM = SourceMgr.getFileManager(); + auto DirEntry = FM.getDirectory(Dir.empty() ? "." : Dir); + if (!DirEntry) + return DirEntry.getError(); + + // Canonicalize the directory. + StringRef CanonicalDir = FM.getCanonicalName(*DirEntry); + if (CanonicalDir != Dir) { + auto CanonicalDirEntry = FM.getDirectory(CanonicalDir); + // Only use the canonicalized path if it resolves to the same entry as the + // original. This is not true if there's a VFS overlay on top of a FS where + // the directory is a symlink. The overlay would not remap the target path + // of the symlink to the same directory entry in that case. + if (CanonicalDirEntry && *CanonicalDirEntry == *DirEntry) { + bool Done = llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir); + (void)Done; + assert(Done && "Path should always start with Dir"); + } + } + + // In theory, the filename component should also be canonicalized if it + // on a case-insensitive filesystem. However, the extra canonicalization is + // expensive and if clang looked up the filename it will always be lowercase. + + // Remove ., remove redundant separators, and switch to native separators. + // This is needed for separators between CanonicalDir and the filename. + llvm::sys::path::remove_dots(Path); + + return std::error_code(); +} + void ModuleMap::addAdditionalModuleMapFile(const Module *M, const FileEntry *ModuleMap) { AdditionalModMaps[M].insert(ModuleMap); @@ -1668,7 +1702,7 @@ retry: break; } } - LLVM_FALLTHROUGH; + [[fallthrough]]; default: Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token); @@ -2026,8 +2060,7 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule->IsSystem = true; if (Attrs.IsExternC) ActiveModule->IsExternC = true; - if (Attrs.NoUndeclaredIncludes || - (!ActiveModule->Parent && ModuleName == "Darwin")) + if (Attrs.NoUndeclaredIncludes) ActiveModule->NoUndeclaredIncludes = true; ActiveModule->Directory = Directory; @@ -2300,6 +2333,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, SourceLocation LeadingLoc) { // We've already consumed the first token. ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader; + if (LeadingToken == MMToken::PrivateKeyword) { Role = ModuleMap::PrivateHeader; // 'private' may optionally be followed by 'textual'. @@ -2307,6 +2341,8 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, LeadingToken = Tok.Kind; consumeToken(); } + } else if (LeadingToken == MMToken::ExcludeKeyword) { + Role = ModuleMap::ExcludedHeader; } if (LeadingToken == MMToken::TextualKeyword) @@ -2340,9 +2376,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, Header.FileName = std::string(Tok.getString()); Header.FileNameLoc = consumeToken(); Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword; - Header.Kind = - (LeadingToken == MMToken::ExcludeKeyword ? Module::HK_Excluded - : Map.headerRoleToKind(Role)); + Header.Kind = Map.headerRoleToKind(Role); // Check whether we already have an umbrella. if (Header.IsUmbrella && ActiveModule->Umbrella) { @@ -2476,8 +2510,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) { SourceMgr.getFileManager().getVirtualFileSystem(); for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E; I != E && !EC; I.increment(EC)) { - if (auto FE = SourceMgr.getFileManager().getFile(I->path())) { - Module::Header Header = {"", std::string(I->path()), *FE}; + if (auto FE = SourceMgr.getFileManager().getOptionalFileRef(I->path())) { + Module::Header Header = {"", std::string(I->path()), FE}; Headers.push_back(std::move(Header)); } } @@ -3033,7 +3067,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, } assert(Target && "Missing target information"); - llvm::Optional<llvm::MemoryBufferRef> Buffer = SourceMgr.getBufferOrNone(ID); + std::optional<llvm::MemoryBufferRef> Buffer = SourceMgr.getBufferOrNone(ID); if (!Buffer) return ParsedModuleMap[File] = true; assert((!Offset || *Offset <= Buffer->getBufferSize()) && |