aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/Lex/ModuleMap.cpp
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r--clang/lib/Lex/ModuleMap.cpp192
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()) &&