Skip to content

[clang][deps][modules] Allocate input file paths lazily #114457

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

Merged
merged 2 commits into from
Nov 11, 2024
Merged
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
9 changes: 7 additions & 2 deletions clang/include/clang/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,20 @@ enum ModuleKind {

/// The input file info that has been loaded from an AST file.
struct InputFileInfo {
std::string FilenameAsRequested;
std::string Filename;
StringRef UnresolvedImportedFilenameAsRequested;
StringRef UnresolvedImportedFilename;

uint64_t ContentHash;
off_t StoredSize;
time_t StoredTime;
bool Overridden;
bool Transient;
bool TopLevel;
bool ModuleMap;

bool isValid() const {
return !UnresolvedImportedFilenameAsRequested.empty();
}
};

/// The input file that has been loaded from this AST file, along with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,6 @@ struct ModuleDeps {
/// additionally appear in \c FileDeps as a dependency.
std::string ClangModuleMapFile;

/// A collection of absolute paths to files that this module directly depends
/// on, not including transitive dependencies.
llvm::StringSet<> FileDeps;

/// A collection of absolute paths to module map files that this module needs
/// to know about. The ordering is significant.
std::vector<std::string> ModuleMapFileDeps;
Expand All @@ -143,13 +139,25 @@ struct ModuleDeps {
/// an entity from this module is used.
llvm::SmallVector<Module::LinkLibrary, 2> LinkLibraries;

/// Invokes \c Cb for all file dependencies of this module. Each provided
/// \c StringRef is only valid within the individual callback invocation.
void forEachFileDep(llvm::function_ref<void(StringRef)> Cb) const;

/// Get (or compute) the compiler invocation that can be used to build this
/// module. Does not include argv[0].
const std::vector<std::string> &getBuildArguments();

private:
friend class ModuleDepCollector;
friend class ModuleDepCollectorPP;

/// The base directory for relative paths in \c FileDeps.
std::string FileDepsBaseDir;

/// A collection of paths to files that this module directly depends on, not
/// including transitive dependencies.
std::vector<std::string> FileDeps;

std::variant<std::monostate, CowCompilerInvocation, std::vector<std::string>>
BuildInfo;
};
Expand Down
41 changes: 17 additions & 24 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2473,7 +2473,7 @@ InputFileInfo ASTReader::getInputFileInfo(ModuleFile &F, unsigned ID) {
return InputFileInfo();

// If we've already loaded this input file, return it.
if (!F.InputFileInfosLoaded[ID - 1].Filename.empty())
if (F.InputFileInfosLoaded[ID - 1].isValid())
return F.InputFileInfosLoaded[ID - 1];

// Go find this input file.
Expand Down Expand Up @@ -2510,21 +2510,11 @@ InputFileInfo ASTReader::getInputFileInfo(ModuleFile &F, unsigned ID) {
R.Transient = static_cast<bool>(Record[4]);
R.TopLevel = static_cast<bool>(Record[5]);
R.ModuleMap = static_cast<bool>(Record[6]);
std::tie(R.FilenameAsRequested, R.Filename) = [&]() {
uint16_t AsRequestedLength = Record[7];

StringRef NameAsRequestedRef = Blob.substr(0, AsRequestedLength);
StringRef NameRef = Blob.substr(AsRequestedLength);

std::string NameAsRequested =
ResolveImportedPathAndAllocate(PathBuf, NameAsRequestedRef, F);
std::string Name = ResolveImportedPathAndAllocate(PathBuf, NameRef, F);

if (Name.empty())
Name = NameAsRequested;

return std::make_pair(std::move(NameAsRequested), std::move(Name));
}();
uint16_t AsRequestedLength = Record[7];
R.UnresolvedImportedFilenameAsRequested = Blob.substr(0, AsRequestedLength);
R.UnresolvedImportedFilename = Blob.substr(AsRequestedLength);
if (R.UnresolvedImportedFilename.empty())
R.UnresolvedImportedFilename = R.UnresolvedImportedFilenameAsRequested;

Expected<llvm::BitstreamEntry> MaybeEntry = Cursor.advance();
if (!MaybeEntry) // FIXME this drops errors on the floor.
Expand Down Expand Up @@ -2576,7 +2566,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
time_t StoredTime = FI.StoredTime;
bool Overridden = FI.Overridden;
bool Transient = FI.Transient;
StringRef Filename = FI.FilenameAsRequested;
auto Filename =
ResolveImportedPath(PathBuf, FI.UnresolvedImportedFilenameAsRequested, F);
uint64_t StoredContentHash = FI.ContentHash;

// For standard C++ modules, we don't need to check the inputs.
Expand All @@ -2592,17 +2583,17 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
Overridden = false;
}

auto File = FileMgr.getOptionalFileRef(Filename, /*OpenFile=*/false);
auto File = FileMgr.getOptionalFileRef(*Filename, /*OpenFile=*/false);

// For an overridden file, create a virtual file with the stored
// size/timestamp.
if ((Overridden || Transient || SkipChecks) && !File)
File = FileMgr.getVirtualFileRef(Filename, StoredSize, StoredTime);
File = FileMgr.getVirtualFileRef(*Filename, StoredSize, StoredTime);

if (!File) {
if (Complain) {
std::string ErrorStr = "could not find file '";
ErrorStr += Filename;
ErrorStr += *Filename;
ErrorStr += "' referenced by AST file '";
ErrorStr += F.FileName;
ErrorStr += "'";
Expand All @@ -2622,7 +2613,7 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
if ((!Overridden && !Transient) && !SkipChecks &&
SM.isFileOverridden(*File)) {
if (Complain)
Error(diag::err_fe_pch_file_overridden, Filename);
Error(diag::err_fe_pch_file_overridden, *Filename);

// After emitting the diagnostic, bypass the overriding file to recover
// (this creates a separate FileEntry).
Expand Down Expand Up @@ -2714,7 +2705,7 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// The top-level PCH is stale.
StringRef TopLevelPCHName(ImportStack.back()->FileName);
Diag(diag::err_fe_ast_file_modified)
<< Filename << moduleKindForDiagnostic(ImportStack.back()->Kind)
<< *Filename << moduleKindForDiagnostic(ImportStack.back()->Kind)
<< TopLevelPCHName << FileChange.Kind
<< (FileChange.Old && FileChange.New)
<< llvm::itostr(FileChange.Old.value_or(0))
Expand All @@ -2723,7 +2714,7 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// Print the import stack.
if (ImportStack.size() > 1) {
Diag(diag::note_pch_required_by)
<< Filename << ImportStack[0]->FileName;
<< *Filename << ImportStack[0]->FileName;
for (unsigned I = 1; I < ImportStack.size(); ++I)
Diag(diag::note_pch_required_by)
<< ImportStack[I-1]->FileName << ImportStack[I]->FileName;
Expand Down Expand Up @@ -2971,8 +2962,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
for (unsigned I = 0; I < N; ++I) {
bool IsSystem = I >= NumUserInputs;
InputFileInfo FI = getInputFileInfo(F, I + 1);
auto FilenameAsRequested = ResolveImportedPath(
PathBuf, FI.UnresolvedImportedFilenameAsRequested, F);
Listener->visitInputFile(
FI.FilenameAsRequested, IsSystem, FI.Overridden,
*FilenameAsRequested, IsSystem, FI.Overridden,
F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule);
}
}
Expand Down
41 changes: 25 additions & 16 deletions clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ using namespace clang;
using namespace tooling;
using namespace dependencies;

void ModuleDeps::forEachFileDep(llvm::function_ref<void(StringRef)> Cb) const {
SmallString<0> PathBuf;
PathBuf.reserve(256);
for (StringRef FileDep : FileDeps) {
auto ResolvedFileDep =
ASTReader::ResolveImportedPath(PathBuf, FileDep, FileDepsBaseDir);
Cb(*ResolvedFileDep);
}
}

const std::vector<std::string> &ModuleDeps::getBuildArguments() {
assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
"Using uninitialized ModuleDeps");
Expand Down Expand Up @@ -596,6 +606,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
serialization::ModuleFile *MF =
MDC.ScanInstance.getASTReader()->getModuleManager().lookup(
*M->getASTFile());
MD.FileDepsBaseDir = MF->BaseDirectory;
MDC.ScanInstance.getASTReader()->visitInputFileInfos(
*MF, /*IncludeSystem=*/true,
[&](const serialization::InputFileInfo &IFI, bool IsSystem) {
Expand All @@ -604,25 +615,30 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
// actual on-disk module map file that allowed inferring the module,
// which is what we need for building the module explicitly
// Let's ignore this file.
if (StringRef(IFI.Filename).ends_with("__inferred_module.map"))
if (IFI.UnresolvedImportedFilename.ends_with("__inferred_module.map"))
return;
MDC.addFileDep(MD, IFI.Filename);
MDC.addFileDep(MD, IFI.UnresolvedImportedFilename);
});

llvm::DenseSet<const Module *> SeenDeps;
addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
addAllSubmoduleDeps(M, MD, SeenDeps);
addAllAffectingClangModules(M, MD, SeenDeps);

SmallString<0> PathBuf;
PathBuf.reserve(256);
MDC.ScanInstance.getASTReader()->visitInputFileInfos(
*MF, /*IncludeSystem=*/true,
[&](const serialization::InputFileInfo &IFI, bool IsSystem) {
if (!(IFI.TopLevel && IFI.ModuleMap))
return;
if (StringRef(IFI.FilenameAsRequested)
.ends_with("__inferred_module.map"))
if (IFI.UnresolvedImportedFilenameAsRequested.ends_with(
"__inferred_module.map"))
return;
MD.ModuleMapFileDeps.emplace_back(IFI.FilenameAsRequested);
auto ResolvedFilenameAsRequested = ASTReader::ResolveImportedPath(
PathBuf, IFI.UnresolvedImportedFilenameAsRequested,
MF->BaseDirectory);
MD.ModuleMapFileDeps.emplace_back(*ResolvedFilenameAsRequested);
});

CowCompilerInvocation CI =
Expand Down Expand Up @@ -779,23 +795,16 @@ static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
void ModuleDepCollector::addFileDep(StringRef Path) {
if (IsStdModuleP1689Format) {
// Within P1689 format, we don't want all the paths to be absolute path
// since it may violate the tranditional make style dependencies info.
FileDeps.push_back(std::string(Path));
// since it may violate the traditional make style dependencies info.
FileDeps.emplace_back(Path);
return;
}

llvm::SmallString<256> Storage;
Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
FileDeps.push_back(std::string(Path));
FileDeps.emplace_back(Path);
}

void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
if (IsStdModuleP1689Format) {
MD.FileDeps.insert(Path);
return;
}

llvm::SmallString<256> Storage;
Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
MD.FileDeps.insert(Path);
MD.FileDeps.emplace_back(Path);
}
2 changes: 1 addition & 1 deletion clang/test/ClangScanDeps/diagnostics.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ module mod { header "mod.h" }
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[HASH_MOD:.*]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/mod.h"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "mod"
Expand Down
18 changes: 9 additions & 9 deletions clang/test/ClangScanDeps/header-search-pruning-transitive.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ module X { header "X.h" }
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[HASH_X:.*]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/X.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/X.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "X"
Expand All @@ -85,11 +85,11 @@ module X { header "X.h" }
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[HASH_Y_WITH_A]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/Y.h",
// CHECK-NEXT: "[[PREFIX]]/a/a.h",
// CHECK-NEXT: "[[PREFIX]]/begin/begin.h",
// CHECK-NEXT: "[[PREFIX]]/end/end.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/a/a.h",
// CHECK-NEXT: "[[PREFIX]]/end/end.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "Y"
Expand Down Expand Up @@ -128,8 +128,8 @@ module X { header "X.h" }
// also has a different context hash from the first version of module X.
// CHECK-NOT: "context-hash": "[[HASH_X]]",
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/X.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/X.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "X"
Expand All @@ -141,10 +141,10 @@ module X { header "X.h" }
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[HASH_Y_WITHOUT_A]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/Y.h",
// CHECK-NEXT: "[[PREFIX]]/begin/begin.h",
// CHECK-NEXT: "[[PREFIX]]/end/end.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/end/end.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "Y"
Expand Down
12 changes: 6 additions & 6 deletions clang/test/ClangScanDeps/link-libraries.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ module transitive {
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/Inputs/frameworks/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/Inputs/frameworks/Framework.framework/Headers/Framework.h"
// CHECK-NEXT: "[[PREFIX]]/Inputs/frameworks/module.modulemap"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [
// CHECK-NEXT: {
Expand All @@ -67,8 +67,8 @@ module transitive {
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/direct.h"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "direct"
Expand All @@ -89,10 +89,10 @@ module transitive {
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/root.h",
// CHECK-NEXT: "[[PREFIX]]/root/textual.h",
// CHECK-NEXT: "[[PREFIX]]/Inputs/frameworks/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/root.h"
// CHECK-NEXT: "[[PREFIX]]/root/textual.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "root"
Expand All @@ -104,7 +104,7 @@ module transitive {
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/transitive.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [
Expand Down
8 changes: 4 additions & 4 deletions clang/test/ClangScanDeps/modules-context-hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
// CHECK: ],
// CHECK-NEXT: "context-hash": "[[HASH_MOD_A:.*]]",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/a/dep.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/mod.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/a/dep.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "mod"
Expand Down Expand Up @@ -72,9 +72,9 @@
// CHECK: ],
// CHECK-NOT: "context-hash": "[[HASH_MOD_A]]",
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/b/dep.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/mod.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/b/dep.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "mod"
Expand Down
4 changes: 2 additions & 2 deletions clang/test/ClangScanDeps/modules-dep-args.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ module Direct { header "direct.h" }
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/direct.h",
// CHECK-NEXT: "[[PREFIX]]/module.modulemap"
// CHECK-NEXT: "[[PREFIX]]/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/direct.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "link-libraries": [],
// CHECK-NEXT: "name": "Direct"
Expand Down
Loading
Loading