Skip to content

[clang][modules] Lazily load by name lookups in module maps #132853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang-tools-extra/modularize/ModularizeUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ std::error_code ModularizeUtilities::loadModuleMap(
Target.get(), *HeaderInfo));

// Parse module.modulemap file into module map.
if (ModMap->loadModuleMapFile(ModuleMapEntry, false, Dir)) {
if (ModMap->parseAndLoadModuleMapFile(ModuleMapEntry, false, Dir)) {
return std::error_code(1, std::generic_category());
}

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ def ModuleImport : DiagGroup<"module-import">;
def ModuleConflict : DiagGroup<"module-conflict">;
def ModuleFileExtension : DiagGroup<"module-file-extension">;
def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
def ModuleMap : DiagGroup<"module-map">;
def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
def NewlineEOF : DiagGroup<"newline-eof">;
def Nullability : DiagGroup<"nullability">;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,12 @@ def warn_pp_date_time : Warning<
ShowInSystemHeader, DefaultIgnore, InGroup<DiagGroup<"date-time">>;

// Module map parsing
def remark_mmap_parse : Remark<
"parsing modulemap '%0'">, ShowInSystemHeader, InGroup<ModuleMap>;
def remark_mmap_load : Remark<
"loading modulemap '%0'">, ShowInSystemHeader, InGroup<ModuleMap>;
def remark_mmap_load_module : Remark<
"loading parsed module '%0'">, ShowInSystemHeader, InGroup<ModuleMap>;
def err_mmap_unknown_token : Error<"skipping stray token">;
def err_mmap_expected_module : Error<"expected module declaration">;
def err_mmap_expected_module_name : Error<"expected module name">;
Expand Down
70 changes: 45 additions & 25 deletions clang/include/clang/Lex/HeaderSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,13 +332,27 @@ class HeaderSearch {
/// The mapping between modules and headers.
mutable ModuleMap ModMap;

struct ModuleMapDirectoryState {
OptionalFileEntryRef ModuleMapFile;
enum {
Parsed,
Loaded,
Invalid,
} Status;
};

/// Describes whether a given directory has a module map in it.
llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap;
llvm::DenseMap<const DirectoryEntry *, ModuleMapDirectoryState>
DirectoryModuleMap;

/// Set of module map files we've already loaded, and a flag indicating
/// whether they were valid or not.
llvm::DenseMap<const FileEntry *, bool> LoadedModuleMaps;

/// Set of module map files we've already parsed, and a flag indicating
/// whether they were valid or not.
llvm::DenseMap<const FileEntry *, bool> ParsedModuleMaps;

// A map of discovered headers with their associated include file name.
llvm::DenseMap<const FileEntry *, llvm::SmallString<64>> IncludeNames;

Expand Down Expand Up @@ -433,11 +447,6 @@ class HeaderSearch {
/// Retrieve the path to the module cache.
StringRef getModuleCachePath() const { return ModuleCachePath; }

/// Consider modules when including files from this directory.
void setDirectoryHasModuleMap(const DirectoryEntry* Dir) {
DirectoryHasModuleMap[Dir] = true;
}

/// Forget everything we know about headers so far.
void ClearFileInfo() {
FileInfo.clear();
Expand Down Expand Up @@ -713,9 +722,10 @@ class HeaderSearch {
/// used to resolve paths within the module (this is required when
/// building the module from preprocessed source).
/// \returns true if an error occurred, false otherwise.
bool loadModuleMapFile(FileEntryRef File, bool IsSystem, FileID ID = FileID(),
unsigned *Offset = nullptr,
StringRef OriginalModuleMapFile = StringRef());
bool parseAndLoadModuleMapFile(FileEntryRef File, bool IsSystem,
FileID ID = FileID(),
unsigned *Offset = nullptr,
StringRef OriginalModuleMapFile = StringRef());

/// Collect the set of all known, top-level modules.
///
Expand Down Expand Up @@ -915,26 +925,31 @@ class HeaderSearch {
size_t getTotalMemory() const;

private:
/// Describes what happened when we tried to load a module map file.
enum LoadModuleMapResult {
/// The module map file had already been loaded.
LMM_AlreadyLoaded,
/// Describes what happened when we tried to load or parse a module map file.
enum ModuleMapResult {
/// The module map file had already been processed.
MMR_AlreadyProcessed,

/// The module map file was loaded by this invocation.
LMM_NewlyLoaded,
/// The module map file was processed by this invocation.
MMR_NewlyProcessed,

/// There is was directory with the given name.
LMM_NoDirectory,
MMR_NoDirectory,

/// There was either no module map file or the module map file was
/// invalid.
LMM_InvalidModuleMap
MMR_InvalidModuleMap
};

LoadModuleMapResult loadModuleMapFileImpl(FileEntryRef File, bool IsSystem,
DirectoryEntryRef Dir,
FileID ID = FileID(),
unsigned *Offset = nullptr);
ModuleMapResult parseAndLoadModuleMapFileImpl(FileEntryRef File,
bool IsSystem,
DirectoryEntryRef Dir,
FileID ID = FileID(),
unsigned *Offset = nullptr);

ModuleMapResult parseModuleMapFileImpl(FileEntryRef File, bool IsSystem,
DirectoryEntryRef Dir,
FileID ID = FileID());

/// Try to load the module map file in the given directory.
///
Expand All @@ -945,8 +960,8 @@ class HeaderSearch {
///
/// \returns The result of attempting to load the module map file from the
/// named directory.
LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem,
bool IsFramework);
ModuleMapResult parseAndLoadModuleMapFile(StringRef DirName, bool IsSystem,
bool IsFramework);

/// Try to load the module map file in the given directory.
///
Expand All @@ -956,8 +971,13 @@ class HeaderSearch {
///
/// \returns The result of attempting to load the module map file from the
/// named directory.
LoadModuleMapResult loadModuleMapFile(DirectoryEntryRef Dir, bool IsSystem,
bool IsFramework);
ModuleMapResult parseAndLoadModuleMapFile(DirectoryEntryRef Dir,
bool IsSystem, bool IsFramework);

ModuleMapResult parseModuleMapFile(StringRef DirName, bool IsSystem,
bool IsFramework);
ModuleMapResult parseModuleMapFile(DirectoryEntryRef Dir, bool IsSystem,
bool IsFramework);
};

/// Apply the header search options to get given HeaderSearch object.
Expand Down
29 changes: 25 additions & 4 deletions clang/include/clang/Lex/ModuleMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/ModuleMapFile.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
Expand Down Expand Up @@ -262,6 +263,18 @@ class ModuleMap {
/// Describes whether we haved loaded a particular file as a module
/// map.
llvm::DenseMap<const FileEntry *, bool> LoadedModuleMap;
llvm::DenseMap<const FileEntry *, const modulemap::ModuleMapFile *>
ParsedModuleMap;

std::vector<std::unique_ptr<modulemap::ModuleMapFile>> ParsedModuleMaps;

/// Map from top level module name to a list of ModuleDecls in the order they
/// were discovered. This allows handling shadowing correctly and diagnosing
/// redefinitions.
llvm::StringMap<SmallVector<std::pair<const modulemap::ModuleMapFile *,
const modulemap::ModuleDecl *>,
1>>
ParsedModules;

/// Resolve the given export declaration into an actual export
/// declaration.
Expand Down Expand Up @@ -478,6 +491,8 @@ class ModuleMap {
/// \returns The named module, if known; otherwise, returns null.
Module *findModule(StringRef Name) const;

Module *findOrLoadModule(StringRef Name);

Module *findOrInferSubmodule(Module *Parent, StringRef Name);

/// Retrieve a module with the given name using lexical name lookup,
Expand Down Expand Up @@ -693,6 +708,11 @@ class ModuleMap {
void addHeader(Module *Mod, Module::Header Header,
ModuleHeaderRole Role, bool Imported = false);

/// Parse a module map without creating `clang::Module` instances.
bool parseModuleMapFile(FileEntryRef File, bool IsSystem,
DirectoryEntryRef Dir, FileID ID = FileID(),
SourceLocation ExternModuleLoc = SourceLocation());

/// Load the given module map file, and record any modules we
/// encounter.
///
Expand All @@ -713,10 +733,11 @@ class ModuleMap {
/// that caused us to load this module map file, if any.
///
/// \returns true if an error occurred, false otherwise.
bool loadModuleMapFile(FileEntryRef File, bool IsSystem,
DirectoryEntryRef HomeDir, FileID ID = FileID(),
unsigned *Offset = nullptr,
SourceLocation ExternModuleLoc = SourceLocation());
bool
parseAndLoadModuleMapFile(FileEntryRef File, bool IsSystem,
DirectoryEntryRef HomeDir, FileID ID = FileID(),
unsigned *Offset = nullptr,
SourceLocation ExternModuleLoc = SourceLocation());

/// Dump the contents of the module map, for debugging purposes.
void dump();
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Lex/ModuleMapFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,17 @@ using TopLevelDecl = std::variant<ModuleDecl, ExternModuleDecl>;
/// This holds many reference types (StringRef, SourceLocation, etc.) whose
/// lifetimes are bound by the SourceManager and FileManager used.
struct ModuleMapFile {
/// The FileID used to parse this module map. This is always a local ID.
FileID ID;

/// The directory in which the module map was discovered. Declarations in
/// the module map are relative to this directory.
OptionalDirectoryEntryRef Dir;

/// Beginning of the file, used for moduleMapFileRead callback.
SourceLocation Start;

bool IsSystem;
std::vector<TopLevelDecl> Decls;

void dump(llvm::raw_ostream &out) const;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,13 +579,13 @@ struct ReadModuleNames : ASTReaderListener {
ModuleMap &MM = PP.getHeaderSearchInfo().getModuleMap();
for (const std::string &LoadedModule : LoadedModules)
MM.cacheModuleLoad(*PP.getIdentifierInfo(LoadedModule),
MM.findModule(LoadedModule));
MM.findOrLoadModule(LoadedModule));
LoadedModules.clear();
}

void markAllUnavailable() {
for (const std::string &LoadedModule : LoadedModules) {
if (Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(
if (Module *M = PP.getHeaderSearchInfo().getModuleMap().findOrLoadModule(
LoadedModule)) {
M->HasIncompatibleModuleFile = true;

Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Frontend/FrontendAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,8 @@ static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem,
}

// Load the module map file.
if (HS.loadModuleMapFile(*ModuleMap, IsSystem, ModuleMapID, &Offset,
PresumedModuleMapFile))
if (HS.parseAndLoadModuleMapFile(*ModuleMap, IsSystem, ModuleMapID, &Offset,
PresumedModuleMapFile))
return true;

if (SrcMgr.getBufferOrFake(ModuleMapID).getBufferSize() == Offset)
Expand Down Expand Up @@ -924,8 +924,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If we were asked to load any module map files, do so now.
for (const auto &Filename : CI.getFrontendOpts().ModuleMapFiles) {
if (auto File = CI.getFileManager().getOptionalFileRef(Filename))
CI.getPreprocessor().getHeaderSearchInfo().loadModuleMapFile(
*File, /*IsSystem*/false);
CI.getPreprocessor().getHeaderSearchInfo().parseAndLoadModuleMapFile(
*File, /*IsSystem*/ false);
else
CI.getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
}
Expand Down
Loading
Loading