aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp699
1 files changed, 415 insertions, 284 deletions
diff --git a/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp b/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp
index bbda1f15a702..eed7eca2e735 100644
--- a/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp
+++ b/contrib/llvm-project/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,
@@ -167,27 +173,27 @@ static void appendSubframeworkPaths(Module *Mod,
return;
// Add Frameworks/Name.framework for each subframework.
- for (unsigned I = Paths.size() - 1; I != 0; --I)
- llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
+ for (StringRef Framework : llvm::drop_begin(llvm::reverse(Paths)))
+ 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;
+ 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();
@@ -229,7 +235,7 @@ Optional<FileEntryRef> ModuleMap::findHeader(
llvm::sys::path::append(FullPathName, RelativePathName);
auto NormalHdrFile = GetFile(FullPathName);
- if (!NormalHdrFile && Directory->getName().endswith(".framework")) {
+ if (!NormalHdrFile && Directory->getName().ends_with(".framework")) {
// The lack of 'framework' keyword in a module declaration it's a simple
// mistake we can diagnose when the header exists within the proper
// framework style path.
@@ -241,17 +247,56 @@ Optional<FileEntryRef> ModuleMap::findHeader(
<< Header.FileName << M->getFullModuleName();
NeedsFramework = true;
}
- return None;
+ return std::nullopt;
}
return NormalHdrFile;
}
+/// Determine whether the given file name is the name of a builtin
+/// header, supplied by Clang to replace, override, or augment existing system
+/// headers.
+static bool isBuiltinHeaderName(StringRef FileName) {
+ return llvm::StringSwitch<bool>(FileName)
+ .Case("float.h", true)
+ .Case("iso646.h", true)
+ .Case("limits.h", true)
+ .Case("stdalign.h", true)
+ .Case("stdarg.h", true)
+ .Case("stdatomic.h", true)
+ .Case("stdbool.h", true)
+ .Case("stddef.h", true)
+ .Case("stdint.h", true)
+ .Case("tgmath.h", true)
+ .Case("unwind.h", true)
+ .Default(false);
+}
+
+/// Determine whether the given module name is the name of a builtin
+/// module that is cyclic with a system module on some platforms.
+static bool isBuiltInModuleName(StringRef ModuleName) {
+ return llvm::StringSwitch<bool>(ModuleName)
+ .Case("_Builtin_float", true)
+ .Case("_Builtin_inttypes", true)
+ .Case("_Builtin_iso646", true)
+ .Case("_Builtin_limits", true)
+ .Case("_Builtin_stdalign", true)
+ .Case("_Builtin_stdarg", true)
+ .Case("_Builtin_stdatomic", true)
+ .Case("_Builtin_stdbool", true)
+ .Case("_Builtin_stddef", true)
+ .Case("_Builtin_stdint", true)
+ .Case("_Builtin_stdnoreturn", true)
+ .Case("_Builtin_tgmath", true)
+ .Case("_Builtin_unwind", true)
+ .Default(false);
+}
+
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();
@@ -260,13 +305,12 @@ void ModuleMap::resolveHeader(Module *Mod,
<< UmbrellaMod->getFullModuleName();
else
// Record this umbrella header.
- setUmbrellaHeader(Mod, *File, RelativePathName.str());
+ setUmbrellaHeaderAsWritten(Mod, *File, Header.FileName,
+ RelativePathName.str());
} else {
- Module::Header H = {std::string(RelativePathName.str()), *File};
- if (Header.Kind == Module::HK_Excluded)
- excludeHeader(Mod, H);
- else
- addHeader(Mod, H, headerKindToRole(Header.Kind));
+ Module::Header H = {Header.FileName, std::string(RelativePathName),
+ *File};
+ 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
@@ -292,7 +336,7 @@ bool ModuleMap::resolveAsBuiltinHeader(
llvm::sys::path::is_absolute(Header.FileName) ||
Mod->isPartOfFramework() || !Mod->IsSystem || Header.IsUmbrella ||
!BuiltinIncludeDir || BuiltinIncludeDir == Mod->Directory ||
- !isBuiltinHeader(Header.FileName))
+ !LangOpts.BuiltinHeadersInSystemModules || !isBuiltinHeaderName(Header.FileName))
return false;
// This is a system module with a top-level header. This header
@@ -304,8 +348,8 @@ bool ModuleMap::resolveAsBuiltinHeader(
if (!File)
return false;
+ Module::Header H = {Header.FileName, Header.FileName, *File};
auto Role = headerKindToRole(Header.Kind);
- Module::Header H = {std::string(Path.str()), *File};
addHeader(Mod, H, Role);
return true;
}
@@ -337,7 +381,7 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
if (Name.empty())
return Name;
- if (!isValidIdentifier(Name)) {
+ if (!isValidAsciiIdentifier(Name)) {
// If we don't already have something with the form of an identifier,
// create a buffer with the sanitized name.
Buffer.clear();
@@ -345,7 +389,7 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
Buffer.push_back('_');
Buffer.reserve(Buffer.size() + Name.size());
for (unsigned I = 0, N = Name.size(); I != N; ++I) {
- if (isIdentifierBody(Name[I]))
+ if (isAsciiIdentifierContinue(Name[I]))
Buffer.push_back(Name[I]);
else
Buffer.push_back('_');
@@ -368,32 +412,19 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
return Name;
}
-/// Determine whether the given file name is the name of a builtin
-/// header, supplied by Clang to replace, override, or augment existing system
-/// headers.
-bool ModuleMap::isBuiltinHeader(StringRef FileName) {
- return llvm::StringSwitch<bool>(FileName)
- .Case("float.h", true)
- .Case("iso646.h", true)
- .Case("limits.h", true)
- .Case("stdalign.h", true)
- .Case("stdarg.h", true)
- .Case("stdatomic.h", true)
- .Case("stdbool.h", true)
- .Case("stddef.h", true)
- .Case("stdint.h", true)
- .Case("tgmath.h", true)
- .Case("unwind.h", true)
- .Default(false);
+bool ModuleMap::isBuiltinHeader(FileEntryRef File) {
+ return File.getDir() == BuiltinIncludeDir && LangOpts.BuiltinHeadersInSystemModules &&
+ isBuiltinHeaderName(llvm::sys::path::filename(File.getName()));
}
-bool ModuleMap::isBuiltinHeader(const FileEntry *File) {
- return File->getDir() == BuiltinIncludeDir &&
- ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()));
+bool ModuleMap::shouldImportRelativeToBuiltinIncludeDir(StringRef FileName,
+ Module *Module) const {
+ return LangOpts.BuiltinHeadersInSystemModules && BuiltinIncludeDir &&
+ Module->IsSystem && !Module->isPartOfFramework() &&
+ isBuiltinHeaderName(FileName);
}
-ModuleMap::HeadersMap::iterator
-ModuleMap::findKnownHeader(const FileEntry *File) {
+ModuleMap::HeadersMap::iterator ModuleMap::findKnownHeader(FileEntryRef File) {
resolveHeaderDirectives(File);
HeadersMap::iterator Known = Headers.find(File);
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
@@ -404,29 +435,27 @@ ModuleMap::findKnownHeader(const FileEntry *File) {
return Known;
}
-ModuleMap::KnownHeader
-ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
- SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs) {
+ModuleMap::KnownHeader ModuleMap::findHeaderInUmbrellaDirs(
+ FileEntryRef File, SmallVectorImpl<DirectoryEntryRef> &IntermediateDirs) {
if (UmbrellaDirs.empty())
return {};
- const DirectoryEntry *Dir = File->getDir();
- assert(Dir && "file in no directory");
+ OptionalDirectoryEntryRef Dir = File.getDir();
// Note: as an egregious but useful hack we use the real path here, because
// frameworks moving from top-level frameworks to embedded frameworks tend
// to be symlinked from the top-level location to the embedded location,
// and we need to resolve lookups as if we had found the embedded location.
- StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
+ StringRef DirName = SourceMgr.getFileManager().getCanonicalName(*Dir);
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
do {
- auto KnownDir = UmbrellaDirs.find(Dir);
+ auto KnownDir = UmbrellaDirs.find(*Dir);
if (KnownDir != UmbrellaDirs.end())
return KnownHeader(KnownDir->second, NormalHeader);
- IntermediateDirs.push_back(Dir);
+ IntermediateDirs.push_back(*Dir);
// Retrieve our parent path.
DirName = llvm::sys::path::parent_path(DirName);
@@ -434,10 +463,7 @@ ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
break;
// Resolve the parent path to a directory entry.
- if (auto DirEntry = SourceMgr.getFileManager().getDirectory(DirName))
- Dir = *DirEntry;
- else
- Dir = nullptr;
+ Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName);
} while (Dir);
return {};
}
@@ -455,10 +481,8 @@ static bool violatesPrivateInclude(Module *RequestingModule,
&Header.getModule()->Headers[Module::HK_Private],
&Header.getModule()->Headers[Module::HK_PrivateTextual]};
for (auto *Hs : HeaderList)
- IsPrivate |=
- std::find_if(Hs->begin(), Hs->end(), [&](const Module::Header &H) {
- return H.Entry == IncFileEnt;
- }) != Hs->end();
+ IsPrivate |= llvm::any_of(
+ *Hs, [&](const Module::Header &H) { return H.Entry == IncFileEnt; });
assert(IsPrivate && "inconsistent headers and roles");
}
#endif
@@ -472,8 +496,7 @@ static Module *getTopLevelOrNull(Module *M) {
void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
bool RequestingModuleIsModuleInterface,
SourceLocation FilenameLoc,
- StringRef Filename,
- const FileEntry *File) {
+ StringRef Filename, FileEntryRef File) {
// No errors for indirect modules. This may be a bit of a problem for modules
// with no source files.
if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))
@@ -481,7 +504,7 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
if (RequestingModule) {
resolveUses(RequestingModule, /*Complain=*/false);
- resolveHeaderDirectives(RequestingModule);
+ resolveHeaderDirectives(RequestingModule, /*File=*/std::nullopt);
}
bool Excluded = false;
@@ -491,6 +514,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();
@@ -521,8 +550,9 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
// We have found a module, but we don't use it.
if (NotUsed) {
- Diags.Report(FilenameLoc, diag::err_undeclared_use_of_module)
- << RequestingModule->getTopLevelModule()->Name << Filename;
+ Diags.Report(FilenameLoc, diag::err_undeclared_use_of_module_indirect)
+ << RequestingModule->getTopLevelModule()->Name << Filename
+ << NotUsed->Name;
return;
}
@@ -541,7 +571,7 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
diag::warn_non_modular_include_in_framework_module :
diag::warn_non_modular_include_in_module;
Diags.Report(FilenameLoc, DiagID) << RequestingModule->getFullModuleName()
- << File->getName();
+ << File.getName();
}
}
@@ -564,12 +594,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) {
+ModuleMap::KnownHeader ModuleMap::findModuleForHeader(FileEntryRef File,
+ bool AllowTextual,
+ bool AllowExcluded) {
auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader {
if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader)
return {};
@@ -581,6 +617,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);
@@ -594,10 +633,10 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File,
}
ModuleMap::KnownHeader
-ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
+ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) {
assert(!Headers.count(File) && "already have a module for this header");
- SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ SmallVector<DirectoryEntryRef, 2> SkippedDirs;
KnownHeader H = findHeaderInUmbrellaDirs(File, SkippedDirs);
if (H) {
Module *Result = H.getModule();
@@ -605,30 +644,29 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
// Search up the module stack until we find a module with an umbrella
// directory.
Module *UmbrellaModule = Result;
- while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ while (!UmbrellaModule->getEffectiveUmbrellaDir() && UmbrellaModule->Parent)
UmbrellaModule = UmbrellaModule->Parent;
if (UmbrellaModule->InferSubmodules) {
- const FileEntry *UmbrellaModuleMap =
- getModuleMapFileForUniquing(UmbrellaModule);
+ FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule);
// Infer submodules for each of the directories we found between
// the directory of the umbrella header and the directory where
// the actual header is located.
bool Explicit = UmbrellaModule->InferExplicitSubmodules;
- for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ for (DirectoryEntryRef SkippedDir : llvm::reverse(SkippedDirs)) {
// Find or create the module that corresponds to this directory name.
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf);
+ llvm::sys::path::stem(SkippedDir.getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
InferredModuleAllowedBy[Result] = UmbrellaModuleMap;
Result->IsInferred = true;
// Associate the module and the directory.
- UmbrellaDirs[SkippedDirs[I-1]] = Result;
+ UmbrellaDirs[SkippedDir] = Result;
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
@@ -639,7 +677,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
// Infer a submodule with the same name as this header file.
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(File->getName()), NameBuf);
+ llvm::sys::path::stem(File.getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
InferredModuleAllowedBy[Result] = UmbrellaModuleMap;
@@ -666,7 +704,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
}
ArrayRef<ModuleMap::KnownHeader>
-ModuleMap::findAllModulesForHeader(const FileEntry *File) {
+ModuleMap::findAllModulesForHeader(FileEntryRef File) {
HeadersMap::iterator Known = findKnownHeader(File);
if (Known != Headers.end())
return Known->second;
@@ -674,26 +712,25 @@ ModuleMap::findAllModulesForHeader(const FileEntry *File) {
if (findOrCreateModuleForHeaderInUmbrellaDir(File))
return Headers.find(File)->second;
- return None;
+ return std::nullopt;
}
ArrayRef<ModuleMap::KnownHeader>
-ModuleMap::findResolvedModulesForHeader(const FileEntry *File) const {
+ModuleMap::findResolvedModulesForHeader(FileEntryRef File) const {
// FIXME: Is this necessary?
resolveHeaderDirectives(File);
auto It = Headers.find(File);
if (It == Headers.end())
- return None;
+ return std::nullopt;
return It->second;
}
-bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
+bool ModuleMap::isHeaderInUnavailableModule(FileEntryRef Header) const {
return isHeaderUnavailableInModule(Header, nullptr);
}
-bool
-ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
- const Module *RequestingModule) const {
+bool ModuleMap::isHeaderUnavailableInModule(
+ FileEntryRef Header, const Module *RequestingModule) const {
resolveHeaderDirectives(Header);
HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end()) {
@@ -702,6 +739,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))) {
@@ -718,8 +758,8 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
return true;
}
- const DirectoryEntry *Dir = Header->getDir();
- SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ OptionalDirectoryEntryRef Dir = Header.getDir();
+ SmallVector<DirectoryEntryRef, 2> SkippedDirs;
StringRef DirName = Dir->getName();
auto IsUnavailable = [&](const Module *M) {
@@ -730,8 +770,7 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
do {
- llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir
- = UmbrellaDirs.find(Dir);
+ auto KnownDir = UmbrellaDirs.find(*Dir);
if (KnownDir != UmbrellaDirs.end()) {
Module *Found = KnownDir->second;
if (IsUnavailable(Found))
@@ -740,16 +779,16 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
// Search up the module stack until we find a module with an umbrella
// directory.
Module *UmbrellaModule = Found;
- while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ while (!UmbrellaModule->getEffectiveUmbrellaDir() &&
+ UmbrellaModule->Parent)
UmbrellaModule = UmbrellaModule->Parent;
if (UmbrellaModule->InferSubmodules) {
- for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ for (DirectoryEntryRef SkippedDir : llvm::reverse(SkippedDirs)) {
// Find or create the module that corresponds to this directory name.
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
- NameBuf);
+ llvm::sys::path::stem(SkippedDir.getName()), NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
@@ -760,7 +799,7 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
// Infer a submodule with the same name as this header file.
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(Header->getName()),
+ llvm::sys::path::stem(Header.getName()),
NameBuf);
Found = lookupModuleQualified(Name, Found);
if (!Found)
@@ -770,7 +809,7 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
return IsUnavailable(Found);
}
- SkippedDirs.push_back(Dir);
+ SkippedDirs.push_back(*Dir);
// Retrieve our parent path.
DirName = llvm::sys::path::parent_path(DirName);
@@ -778,10 +817,7 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
break;
// Resolve the parent path to a directory entry.
- if (auto DirEntry = SourceMgr.getFileManager().getDirectory(DirName))
- Dir = *DirEntry;
- else
- Dir = nullptr;
+ Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName);
} while (Dir);
return false;
@@ -832,12 +868,31 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
return std::make_pair(Result, true);
}
-Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc) {
- PendingSubmodules.emplace_back(
- new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
- /*IsExplicit*/ true, NumCreatedModules++));
- PendingSubmodules.back()->Kind = Module::GlobalModuleFragment;
- return PendingSubmodules.back().get();
+Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
+ Module *Parent) {
+ auto *Result = new Module("<global>", Loc, Parent, /*IsFramework*/ false,
+ /*IsExplicit*/ true, NumCreatedModules++);
+ Result->Kind = Module::ExplicitGlobalModuleFragment;
+ // If the created module isn't owned by a parent, send it to PendingSubmodules
+ // to wait for its parent.
+ if (!Result->Parent)
+ PendingSubmodules.emplace_back(Result);
+ return Result;
+}
+
+Module *
+ModuleMap::createImplicitGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
+ Module *Parent) {
+ assert(Parent && "We should only create an implicit global module fragment "
+ "in a module purview");
+ // Note: Here the `IsExplicit` parameter refers to the semantics in clang
+ // modules. All the non-explicit submodules in clang modules will be exported
+ // too. Here we simplify the implementation by using the concept.
+ auto *Result =
+ new Module("<implicit global>", Loc, Parent, /*IsFramework=*/false,
+ /*IsExplicit=*/false, NumCreatedModules++);
+ Result->Kind = Module::ImplicitGlobalModuleFragment;
+ return Result;
}
Module *
@@ -850,90 +905,98 @@ ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
return Result;
}
-Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
- StringRef Name,
- Module *GlobalModule) {
- assert(LangOpts.CurrentModule == Name && "module name mismatch");
- assert(!Modules[Name] && "redefining existing module");
-
+Module *ModuleMap::createModuleUnitWithKind(SourceLocation Loc, StringRef Name,
+ Module::ModuleKind Kind) {
auto *Result =
new Module(Name, Loc, nullptr, /*IsFramework*/ false,
/*IsExplicit*/ false, NumCreatedModules++);
- Result->Kind = Module::ModuleInterfaceUnit;
- Modules[Name] = SourceModule = Result;
+ Result->Kind = Kind;
- // Reparent the current global module fragment as a submodule of this module.
+ // Reparent any current global module fragment as a submodule of this module.
for (auto &Submodule : PendingSubmodules) {
Submodule->setParent(Result);
Submodule.release(); // now owned by parent
}
PendingSubmodules.clear();
+ return Result;
+}
+
+Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
+ StringRef Name) {
+ assert(LangOpts.CurrentModule == Name && "module name mismatch");
+ assert(!Modules[Name] && "redefining existing module");
+
+ auto *Result =
+ createModuleUnitWithKind(Loc, Name, Module::ModuleInterfaceUnit);
+ Modules[Name] = SourceModule = Result;
// Mark the main source file as being within the newly-created module so that
// declarations and macros are properly visibility-restricted to it.
- auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ auto MainFile = SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID());
assert(MainFile && "no input file for module interface");
- Headers[MainFile].push_back(KnownHeader(Result, PrivateHeader));
+ Headers[*MainFile].push_back(KnownHeader(Result, PrivateHeader));
return Result;
}
-Module *ModuleMap::createHeaderModule(StringRef Name,
- ArrayRef<Module::Header> Headers) {
+Module *ModuleMap::createModuleForImplementationUnit(SourceLocation Loc,
+ StringRef Name) {
assert(LangOpts.CurrentModule == Name && "module name mismatch");
- assert(!Modules[Name] && "redefining existing module");
+ // The interface for this implementation must exist and be loaded.
+ assert(Modules[Name] && Modules[Name]->Kind == Module::ModuleInterfaceUnit &&
+ "creating implementation module without an interface");
+
+ // Create an entry in the modules map to own the implementation unit module.
+ // User module names must not start with a period (so that this cannot clash
+ // with any legal user-defined module name).
+ StringRef IName = ".ImplementationUnit";
+ assert(!Modules[IName] && "multiple implementation units?");
auto *Result =
- new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false,
- /*IsExplicit*/ false, NumCreatedModules++);
- Result->Kind = Module::ModuleInterfaceUnit;
- Modules[Name] = SourceModule = Result;
+ createModuleUnitWithKind(Loc, Name, Module::ModuleImplementationUnit);
+ Modules[IName] = 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);
- }
+ // Check that the main file is present.
+ assert(SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()) &&
+ "no input file for module implementation");
+
+ return Result;
+}
+Module *ModuleMap::createHeaderUnit(SourceLocation Loc, StringRef Name,
+ Module::Header H) {
+ assert(LangOpts.CurrentModule == Name && "module name mismatch");
+ assert(!Modules[Name] && "redefining existing module");
+
+ auto *Result = new Module(Name, Loc, nullptr, /*IsFramework*/ false,
+ /*IsExplicit*/ false, NumCreatedModules++);
+ Result->Kind = Module::ModuleHeaderUnit;
+ Modules[Name] = SourceModule = Result;
+ addHeader(Result, H, NormalHeader);
return Result;
}
/// For a framework module, infer the framework against which we
/// should link.
-static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
- FileManager &FileMgr) {
+static void inferFrameworkLink(Module *Mod) {
assert(Mod->IsFramework && "Can only infer linking for framework modules");
assert(!Mod->isSubFramework() &&
"Can only infer linking for top-level frameworks");
- SmallString<128> LibName;
- LibName += FrameworkDir->getName();
- llvm::sys::path::append(LibName, Mod->Name);
-
- // The library name of a framework has more than one possible extension since
- // the introduction of the text-based dynamic library format. We need to check
- // for both before we give up.
- for (const char *extension : {"", ".tbd"}) {
- llvm::sys::path::replace_extension(LibName, extension);
- if (FileMgr.getFile(LibName)) {
- Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name,
- /*IsFramework=*/true));
- return;
- }
- }
+ StringRef FrameworkName(Mod->Name);
+ FrameworkName.consume_back("_Private");
+ Mod->LinkLibraries.push_back(Module::LinkLibrary(FrameworkName.str(),
+ /*IsFramework=*/true));
}
-Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
+Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
bool IsSystem, Module *Parent) {
Attributes Attrs;
Attrs.IsSystem = IsSystem;
return inferFrameworkModule(FrameworkDir, Attrs, Parent);
}
-Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
+Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
Attributes Attrs, Module *Parent) {
// Note: as an egregious but useful hack we use the real path here, because
// we might be looking at an embedded framework that symlinks out to a
@@ -957,14 +1020,14 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
- const FileEntry *ModuleMapFile = nullptr;
+ FileID ModuleMapFID;
if (!Parent) {
// Determine whether we're allowed to infer a module map.
bool canInfer = false;
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// Figure out the parent path.
StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);
- if (auto ParentDir = FileMgr.getDirectory(Parent)) {
+ if (auto ParentDir = FileMgr.getOptionalDirectoryRef(Parent)) {
// Check whether we have already looked into the parent directory
// for a module map.
llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
@@ -972,10 +1035,10 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
// one.
- bool IsFrameworkDir = Parent.endswith(".framework");
- if (const FileEntry *ModMapFile =
- HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) {
- parseModuleMapFile(ModMapFile, Attrs.IsSystem, *ParentDir);
+ bool IsFrameworkDir = Parent.ends_with(".framework");
+ if (OptionalFileEntryRef ModMapFile =
+ HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) {
+ parseModuleMapFile(*ModMapFile, Attrs.IsSystem, *ParentDir);
inferred = InferredDirectories.find(*ParentDir);
}
@@ -988,16 +1051,15 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
// We're allowed to infer for this directory, but make sure it's okay
// to infer this particular module.
StringRef Name = llvm::sys::path::stem(FrameworkDirName);
- canInfer = std::find(inferred->second.ExcludedModules.begin(),
- inferred->second.ExcludedModules.end(),
- Name) == inferred->second.ExcludedModules.end();
+ canInfer =
+ !llvm::is_contained(inferred->second.ExcludedModules, Name);
Attrs.IsSystem |= inferred->second.Attrs.IsSystem;
Attrs.IsExternC |= inferred->second.Attrs.IsExternC;
Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive;
Attrs.NoUndeclaredIncludes |=
inferred->second.Attrs.NoUndeclaredIncludes;
- ModuleMapFile = inferred->second.ModuleMapFile;
+ ModuleMapFID = inferred->second.ModuleMapFID;
}
}
}
@@ -1005,12 +1067,12 @@ 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 {
+ ModuleMapFID = getModuleMapFileIDForUniquing(Parent);
+ }
// Look for an umbrella header.
- SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
+ SmallString<128> UmbrellaName = FrameworkDir.getName();
llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");
auto UmbrellaHeader = FileMgr.getOptionalFileRef(UmbrellaName);
@@ -1023,7 +1085,7 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false,
NumCreatedModules++);
- InferredModuleAllowedBy[Result] = ModuleMapFile;
+ InferredModuleAllowedBy[Result] = ModuleMapFID;
Result->IsInferred = true;
if (!Parent) {
if (LangOpts.CurrentModule == ModuleName)
@@ -1038,11 +1100,14 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
Result->NoUndeclaredIncludes |= Attrs.NoUndeclaredIncludes;
Result->Directory = FrameworkDir;
+ // Chop off the first framework bit, as that is implied.
+ StringRef RelativePath = UmbrellaName.str().substr(
+ Result->getTopLevelModule()->Directory->getName().size());
+ RelativePath = llvm::sys::path::relative_path(RelativePath);
+
// umbrella header "umbrella-header-name"
- //
- // The "Headers/" component of the name is implied because this is
- // a framework module.
- setUmbrellaHeader(Result, *UmbrellaHeader, ModuleName + ".h");
+ setUmbrellaHeaderAsWritten(Result, *UmbrellaHeader, ModuleName + ".h",
+ RelativePath);
// export *
Result->Exports.push_back(Module::ExportDecl(nullptr, true));
@@ -1053,8 +1118,7 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
// Look for subframeworks.
std::error_code EC;
- SmallString<128> SubframeworksDirName
- = StringRef(FrameworkDir->getName());
+ SmallString<128> SubframeworksDirName = FrameworkDir.getName();
llvm::sys::path::append(SubframeworksDirName, "Frameworks");
llvm::sys::path::native(SubframeworksDirName);
llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
@@ -1062,11 +1126,10 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
Dir = FS.dir_begin(SubframeworksDirName, EC),
DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- if (!StringRef(Dir->path()).endswith(".framework"))
+ if (!StringRef(Dir->path()).ends_with(".framework"))
continue;
- if (auto SubframeworkDir =
- FileMgr.getDirectory(Dir->path())) {
+ if (auto SubframeworkDir = FileMgr.getOptionalDirectoryRef(Dir->path())) {
// Note: as an egregious but useful hack, we use the real path here and
// check whether it is actually a subdirectory of the parent directory.
// This will not be the case if the 'subframework' is actually a symlink
@@ -1099,9 +1162,8 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
// If the module is a top-level framework, automatically link against the
// framework.
- if (!Result->isSubFramework()) {
- inferFrameworkLink(Result, FrameworkDir, FileMgr);
- }
+ if (!Result->isSubFramework())
+ inferFrameworkLink(Result);
return Result;
}
@@ -1121,22 +1183,28 @@ Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
return Result;
}
-void ModuleMap::setUmbrellaHeader(Module *Mod, FileEntryRef UmbrellaHeader,
- Twine NameAsWritten) {
+void ModuleMap::setUmbrellaHeaderAsWritten(
+ Module *Mod, FileEntryRef UmbrellaHeader, const Twine &NameAsWritten,
+ const Twine &PathRelativeToRootModuleDirectory) {
Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
- Mod->Umbrella = &UmbrellaHeader.getMapEntry();
+ Mod->Umbrella = UmbrellaHeader;
Mod->UmbrellaAsWritten = NameAsWritten.str();
+ Mod->UmbrellaRelativeToRootModuleDirectory =
+ PathRelativeToRootModuleDirectory.str();
UmbrellaDirs[UmbrellaHeader.getDir()] = Mod;
// Notify callbacks that we just added a new header.
for (const auto &Cb : Callbacks)
- Cb->moduleMapAddUmbrellaHeader(&SourceMgr.getFileManager(), UmbrellaHeader);
+ Cb->moduleMapAddUmbrellaHeader(UmbrellaHeader);
}
-void ModuleMap::setUmbrellaDir(Module *Mod, DirectoryEntryRef UmbrellaDir,
- Twine NameAsWritten) {
- Mod->Umbrella = &UmbrellaDir.getMapEntry();
+void ModuleMap::setUmbrellaDirAsWritten(
+ Module *Mod, DirectoryEntryRef UmbrellaDir, const Twine &NameAsWritten,
+ const Twine &PathRelativeToRootModuleDirectory) {
+ Mod->Umbrella = UmbrellaDir;
Mod->UmbrellaAsWritten = NameAsWritten.str();
+ Mod->UmbrellaRelativeToRootModuleDirectory =
+ PathRelativeToRootModuleDirectory.str();
UmbrellaDirs[UmbrellaDir] = Mod;
}
@@ -1180,25 +1248,35 @@ void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const {
auto BySize = LazyHeadersBySize.find(File->getSize());
if (BySize != LazyHeadersBySize.end()) {
for (auto *M : BySize->second)
- resolveHeaderDirectives(M);
+ resolveHeaderDirectives(M, File);
LazyHeadersBySize.erase(BySize);
}
auto ByModTime = LazyHeadersByModTime.find(File->getModificationTime());
if (ByModTime != LazyHeadersByModTime.end()) {
for (auto *M : ByModTime->second)
- resolveHeaderDirectives(M);
+ resolveHeaderDirectives(M, File);
LazyHeadersByModTime.erase(ByModTime);
}
}
-void ModuleMap::resolveHeaderDirectives(Module *Mod) const {
+void ModuleMap::resolveHeaderDirectives(
+ Module *Mod, std::optional<const FileEntry *> File) const {
bool NeedsFramework = false;
- for (auto &Header : Mod->UnresolvedHeaders)
- // This operation is logically const; we're just changing how we represent
- // the header information for this file.
- const_cast<ModuleMap*>(this)->resolveHeader(Mod, Header, NeedsFramework);
- Mod->UnresolvedHeaders.clear();
+ SmallVector<Module::UnresolvedHeaderDirective, 1> NewHeaders;
+ 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) ||
+ (Header.Size && Header.Size != Size)))
+ NewHeaders.push_back(Header);
+ else
+ // This operation is logically const; we're just changing how we represent
+ // the header information for this file.
+ const_cast<ModuleMap *>(this)->resolveHeader(Mod, Header, NeedsFramework);
+ }
+ Mod->UnresolvedHeaders.swap(NewHeaders);
}
void ModuleMap::addHeader(Module *Mod, Module::Header Header,
@@ -1209,15 +1287,13 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header,
// FIXME: Should we diagnose if a header is listed twice in the
// same module definition?
auto &HeaderList = Headers[Header.Entry];
- for (auto H : HeaderList)
- if (H == KH)
- return;
+ if (llvm::is_contained(HeaderList, KH))
+ return;
HeaderList.push_back(KH);
Mod->Headers[headerRoleToKind(Role)].push_back(Header);
- bool isCompilingModuleHeader =
- LangOpts.isCompilingModule() && Mod->getTopLevelModule() == SourceModule;
+ bool isCompilingModuleHeader = Mod->isForBuilding(LangOpts);
if (!Imported || isCompilingModuleHeader) {
// When we import HeaderFileInfo, the external source is expected to
// set the isModuleHeader flag itself.
@@ -1227,43 +1303,74 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header,
// Notify callbacks that we just added a new header.
for (const auto &Cb : Callbacks)
- Cb->moduleMapAddHeader(Header.Entry->getName());
+ 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];
+FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const {
+ if (Module->DefinitionLoc.isInvalid())
+ return {};
- Mod->Headers[Module::HK_Excluded].push_back(std::move(Header));
+ return SourceMgr.getFileID(Module->DefinitionLoc);
}
-const FileEntry *
+OptionalFileEntryRef
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
- if (Module->DefinitionLoc.isInvalid())
- return nullptr;
-
- return SourceMgr.getFileEntryForID(
- SourceMgr.getFileID(Module->DefinitionLoc));
+ return SourceMgr.getFileEntryRefForID(getContainingModuleMapFileID(Module));
}
-const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
+FileID ModuleMap::getModuleMapFileIDForUniquing(const Module *M) const {
if (M->IsInferred) {
assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");
return InferredModuleAllowedBy.find(M)->second;
}
- return getContainingModuleMapFile(M);
+ return getContainingModuleMapFileID(M);
}
-void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) {
+OptionalFileEntryRef
+ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
+ return SourceMgr.getFileEntryRefForID(getModuleMapFileIDForUniquing(M));
+}
+
+void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) {
assert(M->IsInferred && "module not inferred");
- InferredModuleAllowedBy[M] = ModMap;
+ InferredModuleAllowedBy[M] = ModMapFID;
+}
+
+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.ends_with(".framework"))
+ Dir = Parent;
+ }
+
+ FileManager &FM = SourceMgr.getFileManager();
+ auto DirEntry = FM.getDirectoryRef(Dir.empty() ? "." : Dir);
+ if (!DirEntry)
+ return llvm::errorToErrorCode(DirEntry.takeError());
+
+ // Canonicalize the directory.
+ StringRef CanonicalDir = FM.getCanonicalName(*DirEntry);
+ if (CanonicalDir != Dir)
+ llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir);
+
+ // 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) {
+ FileEntryRef ModuleMap) {
AdditionalModMaps[M].insert(ModuleMap);
}
@@ -1277,7 +1384,7 @@ LLVM_DUMP_METHOD void ModuleMap::dump() {
llvm::errs() << "Headers:";
for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
H != HEnd; ++H) {
- llvm::errs() << " \"" << H->first->getName() << "\" -> ";
+ llvm::errs() << " \"" << H->first.getName() << "\" -> ";
for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(),
E = H->second.end();
I != E; ++I) {
@@ -1303,16 +1410,17 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
}
bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
- auto Unresolved = std::move(Mod->UnresolvedDirectUses);
- Mod->UnresolvedDirectUses.clear();
+ auto *Top = Mod->getTopLevelModule();
+ auto Unresolved = std::move(Top->UnresolvedDirectUses);
+ Top->UnresolvedDirectUses.clear();
for (auto &UDU : Unresolved) {
- Module *DirectUse = resolveModuleId(UDU, Mod, Complain);
+ Module *DirectUse = resolveModuleId(UDU, Top, Complain);
if (DirectUse)
- Mod->DirectUses.push_back(DirectUse);
+ Top->DirectUses.push_back(DirectUse);
else
- Mod->UnresolvedDirectUses.push_back(UDU);
+ Top->UnresolvedDirectUses.push_back(UDU);
}
- return !Mod->UnresolvedDirectUses.empty();
+ return !Top->UnresolvedDirectUses.empty();
}
bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
@@ -1369,7 +1477,7 @@ namespace clang {
RSquare
} Kind;
- unsigned Location;
+ SourceLocation::UIntTy Location;
unsigned StringLength;
union {
// If Kind != IntegerLiteral.
@@ -1414,14 +1522,14 @@ namespace clang {
ModuleMap &Map;
/// The current module map file.
- const FileEntry *ModuleMapFile;
+ FileID ModuleMapFID;
/// Source location of most recent parsed module declaration
SourceLocation CurrModuleDeclLoc;
/// The directory that file names in this module map file should
/// be resolved relative to.
- const DirectoryEntry *Directory;
+ DirectoryEntryRef Directory;
/// Whether this module map is in a system header directory.
bool IsSystem;
@@ -1456,8 +1564,6 @@ namespace clang {
/// (or the end of the file).
void skipUntil(MMToken::TokenKind K);
- using ModuleId = SmallVector<std::pair<std::string, SourceLocation>, 2>;
-
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseExternModuleDecl();
@@ -1484,13 +1590,12 @@ namespace clang {
bool parseOptionalAttributes(Attributes &Attrs);
public:
- explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
- const TargetInfo *Target, DiagnosticsEngine &Diags,
- ModuleMap &Map, const FileEntry *ModuleMapFile,
- const DirectoryEntry *Directory, bool IsSystem)
+ ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
+ const TargetInfo *Target, DiagnosticsEngine &Diags,
+ ModuleMap &Map, FileID ModuleMapFID,
+ DirectoryEntryRef Directory, bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
- ModuleMapFile(ModuleMapFile), Directory(Directory),
- IsSystem(IsSystem) {
+ ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) {
Tok.clear();
consumeToken();
}
@@ -1605,7 +1710,7 @@ retry:
SpellingBuffer.resize(LToken.getLength() + 1);
const char *Start = SpellingBuffer.data();
unsigned Length =
- Lexer::getSpelling(LToken, Start, SourceMgr, L.getLangOpts());
+ Lexer::getSpelling(LToken, Start, SourceMgr, Map.LangOpts);
uint64_t Value;
if (StringRef(Start, Length).getAsInteger(0, Value)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
@@ -1638,7 +1743,7 @@ retry:
break;
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
@@ -1765,7 +1870,7 @@ void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,
continue;
SmallString<128> FullName(ActiveModule->getFullModuleName());
- if (!FullName.startswith(M->Name) && !FullName.endswith("Private"))
+ if (!FullName.starts_with(M->Name) && !FullName.ends_with("Private"))
continue;
SmallString<128> FixedPrivModDecl;
SmallString<128> Canonical(M->Name);
@@ -1910,11 +2015,13 @@ void ModuleMapParser::parseModuleDecl() {
}
if (TopLevelModule &&
- ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) {
- assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) &&
+ ModuleMapFID != Map.getContainingModuleMapFileID(TopLevelModule)) {
+ assert(ModuleMapFID !=
+ Map.getModuleMapFileIDForUniquing(TopLevelModule) &&
"submodule defined in same file as 'module *' that allowed its "
"top-level module");
- Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile);
+ Map.addAdditionalModuleMapFile(
+ TopLevelModule, *SourceMgr.getFileEntryRefForID(ModuleMapFID));
}
}
@@ -1939,10 +2046,28 @@ void ModuleMapParser::parseModuleDecl() {
Module *ShadowingModule = nullptr;
if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
// We might see a (re)definition of a module that we already have a
- // definition for in two cases:
+ // definition for in four cases:
// - If we loaded one definition from an AST file and we've just found a
// corresponding definition in a module map file, or
- bool LoadedFromASTFile = Existing->DefinitionLoc.isInvalid();
+ bool LoadedFromASTFile = Existing->IsFromModuleFile;
+ // - If we previously inferred this module from different module map file.
+ bool Inferred = Existing->IsInferred;
+ // - If we're building a framework that vends a module map, we might've
+ // previously seen the one in intermediate products and now the system
+ // one.
+ // FIXME: If we're parsing module map file that looks like this:
+ // framework module FW { ... }
+ // module FW.Sub { ... }
+ // We can't check the framework qualifier, since it's not attached to
+ // the definition of Sub. Checking that qualifier on \c Existing is
+ // not correct either, since we might've previously seen:
+ // module FW { ... }
+ // module FW.Sub { ... }
+ // We should enforce consistency of redefinitions so that we can rely
+ // that \c Existing is part of a framework iff the redefinition of FW
+ // we have just skipped had it too. Once we do that, stop checking
+ // the local framework qualifier and only rely on \c Existing.
+ bool PartOfFramework = Framework || Existing->isPartOfFramework();
// - If we're building a (preprocessed) module and we've just loaded the
// module map file from which it was created.
bool ParsedAsMainInput =
@@ -1950,7 +2075,8 @@ void ModuleMapParser::parseModuleDecl() {
Map.LangOpts.CurrentModule == ModuleName &&
SourceMgr.getDecomposedLoc(ModuleNameLoc).first !=
SourceMgr.getDecomposedLoc(Existing->DefinitionLoc).first;
- if (!ActiveModule && (LoadedFromASTFile || ParsedAsMainInput)) {
+ if (LoadedFromASTFile || Inferred || PartOfFramework || ParsedAsMainInput) {
+ ActiveModule = PreviousActiveModule;
// Skip the module definition.
skipUntil(MMToken::RBrace);
if (Tok.is(MMToken::RBrace))
@@ -1996,14 +2122,14 @@ 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;
- StringRef MapFileName(ModuleMapFile->getName());
- if (MapFileName.endswith("module.private.modulemap") ||
- MapFileName.endswith("module_private.map")) {
+ StringRef MapFileName(
+ SourceMgr.getFileEntryRefForID(ModuleMapFID)->getName());
+ if (MapFileName.ends_with("module.private.modulemap") ||
+ MapFileName.ends_with("module_private.map")) {
ActiveModule->ModuleMapIsPrivate = true;
}
@@ -2106,9 +2232,8 @@ void ModuleMapParser::parseModuleDecl() {
// If the active module is a top-level framework, and there are no link
// libraries, automatically link against the framework.
if (ActiveModule->IsFramework && !ActiveModule->isSubFramework() &&
- ActiveModule->LinkLibraries.empty()) {
- inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
- }
+ ActiveModule->LinkLibraries.empty())
+ inferFrameworkLink(ActiveModule);
// If the module meets all requirements but is still unavailable, mark the
// whole tree as unavailable to prevent it from building.
@@ -2159,16 +2284,16 @@ void ModuleMapParser::parseExternModuleDecl() {
StringRef FileNameRef = FileName;
SmallString<128> ModuleMapFileName;
if (llvm::sys::path::is_relative(FileNameRef)) {
- ModuleMapFileName += Directory->getName();
+ ModuleMapFileName += Directory.getName();
llvm::sys::path::append(ModuleMapFileName, FileName);
FileNameRef = ModuleMapFileName;
}
- if (auto File = SourceMgr.getFileManager().getFile(FileNameRef))
+ if (auto File = SourceMgr.getFileManager().getOptionalFileRef(FileNameRef))
Map.parseModuleMapFile(
- *File, /*IsSystem=*/false,
+ *File, IsSystem,
Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
? Directory
- : (*File)->getDir(),
+ : File->getDir(),
FileID(), nullptr, ExternLoc);
}
@@ -2270,6 +2395,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'.
@@ -2277,6 +2403,8 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
LeadingToken = Tok.Kind;
consumeToken();
}
+ } else if (LeadingToken == MMToken::ExcludeKeyword) {
+ Role = ModuleMap::ExcludedHeader;
}
if (LeadingToken == MMToken::TextualKeyword)
@@ -2310,12 +2438,11 @@ 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) {
+ if (Header.IsUmbrella &&
+ !std::holds_alternative<std::monostate>(ActiveModule->Umbrella)) {
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
@@ -2378,17 +2505,23 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
}
bool NeedsFramework = false;
- Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);
-
- if (NeedsFramework && ActiveModule)
+ // Don't add headers to the builtin modules if the builtin headers belong to
+ // the system modules, with the exception of __stddef_max_align_t.h which
+ // always had its own module.
+ if (!Map.LangOpts.BuiltinHeadersInSystemModules ||
+ !isBuiltInModuleName(ActiveModule->getTopLevelModuleName()) ||
+ ActiveModule->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}))
+ Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);
+
+ if (NeedsFramework)
Diags.Report(CurrModuleDeclLoc, diag::note_mmap_add_framework_keyword)
<< ActiveModule->getFullModuleName()
<< FixItHint::CreateReplacement(CurrModuleDeclLoc, "framework module");
}
-static int compareModuleHeaders(const Module::Header *A,
- const Module::Header *B) {
- return A->NameAsWritten.compare(B->NameAsWritten);
+static bool compareModuleHeaders(const Module::Header &A,
+ const Module::Header &B) {
+ return A.NameAsWritten < B.NameAsWritten;
}
/// Parse an umbrella directory declaration.
@@ -2405,10 +2538,11 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
std::string DirName = std::string(Tok.getString());
+ std::string DirNameAsWritten = DirName;
SourceLocation DirNameLoc = consumeToken();
// Check whether we already have an umbrella.
- if (ActiveModule->Umbrella) {
+ if (!std::holds_alternative<std::monostate>(ActiveModule->Umbrella)) {
Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
@@ -2416,16 +2550,14 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
// Look for this file.
- Optional<DirectoryEntryRef> Dir;
+ OptionalDirectoryEntryRef Dir;
if (llvm::sys::path::is_absolute(DirName)) {
- if (auto D = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName))
- Dir = *D;
+ Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName);
} else {
SmallString<128> PathName;
- PathName = Directory->getName();
+ PathName = Directory.getName();
llvm::sys::path::append(PathName, DirName);
- if (auto D = SourceMgr.getFileManager().getOptionalDirectoryRef(PathName))
- Dir = *D;
+ Dir = SourceMgr.getFileManager().getOptionalDirectoryRef(PathName);
}
if (!Dir) {
@@ -2446,13 +2578,13 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E;
I != E && !EC; I.increment(EC)) {
if (auto FE = SourceMgr.getFileManager().getOptionalFileRef(I->path())) {
- Module::Header Header = {std::string(I->path()), *FE};
+ Module::Header Header = {"", std::string(I->path()), *FE};
Headers.push_back(std::move(Header));
}
}
// Sort header paths so that the pcm doesn't depend on iteration order.
- llvm::array_pod_sort(Headers.begin(), Headers.end(), compareModuleHeaders);
+ std::stable_sort(Headers.begin(), Headers.end(), compareModuleHeaders);
for (auto &Header : Headers)
Map.addHeader(ActiveModule, std::move(Header), ModuleMap::TextualHeader);
@@ -2467,7 +2599,7 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
// Record this umbrella directory.
- Map.setUmbrellaDir(ActiveModule, *Dir, DirName);
+ Map.setUmbrellaDirAsWritten(ActiveModule, *Dir, DirNameAsWritten, DirName);
}
/// Parse a module export declaration.
@@ -2731,7 +2863,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
if (ActiveModule) {
// Inferred modules must have umbrella directories.
if (!Failed && ActiveModule->IsAvailable &&
- !ActiveModule->getUmbrellaDir()) {
+ !ActiveModule->getEffectiveUmbrellaDir()) {
Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
Failed = true;
}
@@ -2781,7 +2913,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
// We'll be inferring framework modules for this directory.
Map.InferredDirectories[Directory].InferModules = true;
Map.InferredDirectories[Directory].Attrs = Attrs;
- Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
+ Map.InferredDirectories[Directory].ModuleMapFID = ModuleMapFID;
// FIXME: Handle the 'framework' keyword.
}
@@ -2984,8 +3116,8 @@ bool ModuleMapParser::parseModuleMapFile() {
} while (true);
}
-bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
- const DirectoryEntry *Dir, FileID ID,
+bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem,
+ DirectoryEntryRef Dir, FileID ID,
unsigned *Offset,
SourceLocation ExternModuleLoc) {
assert(Target && "Missing target information");
@@ -3002,7 +3134,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()) &&
@@ -3014,8 +3146,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
Buffer->getBufferStart() + (Offset ? *Offset : 0),
Buffer->getBufferEnd());
SourceLocation Start = L.getSourceLocation();
- ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
- IsSystem);
+ ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem);
bool Result = Parser.parseModuleMapFile();
ParsedModuleMap[File] = Result;
@@ -3027,7 +3158,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
// Notify callbacks that we parsed it.
for (const auto &Cb : Callbacks)
- Cb->moduleMapFileRead(Start, *File, IsSystem);
+ Cb->moduleMapFileRead(Start, File, IsSystem);
return Result;
}