diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp | 699 |
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 ⤅ /// 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; } |