From 2838b2b6bda39a220d80ba7b9fc63cecd18825a6 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 22 Jul 2025 10:10:39 -0700 Subject: [PATCH 01/41] [clang][deps] Remove dependency on `tooling::ToolAction` (#149904) The dependency scanner was initially using a fair amount of infrastructure provided by the `clangTooling` library. Over time, the needs for bespoke handling of command lines grew and the overlap with the tooling library kept shrinking. I don't think the library provides any value anymore. I decided to remove the dependency and only reimplement the small bits required by the scanner. This allowed for a nice simplification, where we no longer need to create temporary dummy `FileManager` instances (mis-named as `DriverFileMgr` in some parts) and `SourceManager` instances to attach to the `DiagnosticsEngine`. That code was copied from the tooling library to support `DiagnosticConsumers` that expect these to exist. The scanner uses a closed set of consumers and none need these objects to exist. The motivation for this (hopefully NFC) patch are some new restrictions to how VFS's can be propagated in Clang that I'm working on. --- .../DependencyScanningWorker.cpp | 86 ++++++++----------- 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 0420a83191922..5e0b5df50fe57 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -28,7 +28,6 @@ #include "clang/Tooling/DependencyScanning/InProcessModuleCache.h" #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" #include "clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h" -#include "clang/Tooling/Tooling.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/CAS/CASProvidingFileSystem.h" #include "llvm/CAS/CachingOnDiskFileSystem.h" @@ -506,7 +505,7 @@ class CASDependencyDirectivesGetter : public DependencyDirectivesGetter { /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. -class DependencyScanningAction : public tooling::ToolAction { +class DependencyScanningAction { public: DependencyScanningAction( DependencyScanningService &Service, StringRef WorkingDirectory, @@ -514,26 +513,23 @@ class DependencyScanningAction : public tooling::ToolAction { llvm::IntrusiveRefCntPtr DepFS, llvm::IntrusiveRefCntPtr DepCASFS, llvm::IntrusiveRefCntPtr CacheFS, - bool DisableFree, bool EmitDependencyFile, + bool EmitDependencyFile, bool DiagGenerationAsCompilation, const CASOptions &CASOpts, std::optional ModuleName = std::nullopt, raw_ostream *VerboseOS = nullptr) : Service(Service), WorkingDirectory(WorkingDirectory), Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)), DepCASFS(std::move(DepCASFS)), CacheFS(std::move(CacheFS)), - DisableFree(DisableFree), CASOpts(CASOpts), EmitDependencyFile(EmitDependencyFile), DiagGenerationAsCompilation(DiagGenerationAsCompilation), ModuleName(ModuleName), VerboseOS(VerboseOS) {} bool runInvocation(std::shared_ptr Invocation, - FileManager *DriverFileMgr, + IntrusiveRefCntPtr FS, std::shared_ptr PCHContainerOps, - DiagnosticConsumer *DiagConsumer) override { + DiagnosticConsumer *DiagConsumer) { // Make a deep copy of the original Clang invocation. CompilerInvocation OriginalInvocation(*Invocation); - // Restore the value of DisableFree, which may be modified by Tooling. - OriginalInvocation.getFrontendOpts().DisableFree = DisableFree; if (any(Service.getOptimizeArgs() & ScanningOptimizations::Macros)) canonicalizeDefines(OriginalInvocation.getPreprocessorOpts()); @@ -574,8 +570,8 @@ class DependencyScanningAction : public tooling::ToolAction { if (!DiagGenerationAsCompilation) sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); assert(!DiagConsumerFinished && "attempt to reuse finished consumer"); - ScanInstance.createDiagnostics(DriverFileMgr->getVirtualFileSystem(), - DiagConsumer, /*ShouldOwnClient=*/false); + ScanInstance.createDiagnostics(*FS, DiagConsumer, + /*ShouldOwnClient=*/false); if (!ScanInstance.hasDiagnostics()) return false; if (VerboseOS) @@ -588,6 +584,7 @@ class DependencyScanningAction : public tooling::ToolAction { ScanInstance.getHeaderSearchOpts().BuildSessionTimestamp = Service.getBuildSessionTimestamp(); + ScanInstance.getFrontendOpts().DisableFree = false; ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false; ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false; // This will prevent us compiling individual modules asynchronously since @@ -600,9 +597,9 @@ class DependencyScanningAction : public tooling::ToolAction { any(Service.getOptimizeArgs() & ScanningOptimizations::VFS); // Support for virtual file system overlays. - auto FS = createVFSFromCompilerInvocation( - ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), - DriverFileMgr->getVirtualFileSystemPtr()); + FS = createVFSFromCompilerInvocation(ScanInstance.getInvocation(), + ScanInstance.getDiagnostics(), + std::move(FS)); // Create a new FileManager to match the invocation's FileSystemOptions. auto *FileMgr = ScanInstance.createFileManager(FS); @@ -776,9 +773,6 @@ class DependencyScanningAction : public tooling::ToolAction { LastCC1Arguments = OriginalInvocation.getCC1CommandLine(); LastCC1CacheKey = Controller.getCacheKey(OriginalInvocation); - // Propagate the statistics to the parent FileManager. - DriverFileMgr->AddStats(ScanInstance.getFileManager()); - return true; } @@ -819,7 +813,6 @@ class DependencyScanningAction : public tooling::ToolAction { llvm::IntrusiveRefCntPtr DepFS; llvm::IntrusiveRefCntPtr DepCASFS; llvm::IntrusiveRefCntPtr CacheFS; - bool DisableFree; const CASOptions &CASOpts; bool EmitDependencyFile = false; bool DiagGenerationAsCompilation; @@ -922,15 +915,14 @@ llvm::Error DependencyScanningWorker::computeDependencies( } static bool forEachDriverJob( - ArrayRef ArgStrs, DiagnosticsEngine &Diags, FileManager &FM, + ArrayRef ArgStrs, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr FS, llvm::function_ref Callback) { SmallVector Argv; Argv.reserve(ArgStrs.size()); for (const std::string &Arg : ArgStrs) Argv.push_back(Arg.c_str()); - llvm::vfs::FileSystem *FS = &FM.getVirtualFileSystem(); - std::unique_ptr Driver = std::make_unique( Argv[0], llvm::sys::getDefaultTargetTriple(), Diags, "clang LLVM compiler", FS); @@ -940,7 +932,8 @@ static bool forEachDriverJob( bool CLMode = driver::IsClangCL( driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1))); - if (llvm::Error E = driver::expandResponseFiles(Argv, CLMode, Alloc, FS)) { + if (llvm::Error E = + driver::expandResponseFiles(Argv, CLMode, Alloc, FS.get())) { Diags.Report(diag::err_drv_expand_response_file) << llvm::toString(std::move(E)); return false; @@ -963,17 +956,25 @@ static bool forEachDriverJob( static bool createAndRunToolInvocation( std::vector CommandLine, DependencyScanningAction &Action, - FileManager &FM, + IntrusiveRefCntPtr FS, std::shared_ptr &PCHContainerOps, DiagnosticsEngine &Diags, DependencyConsumer &Consumer) { // Save executable path before providing CommandLine to ToolInvocation std::string Executable = CommandLine[0]; - ToolInvocation Invocation(std::move(CommandLine), &Action, &FM, - PCHContainerOps); - Invocation.setDiagnosticConsumer(Diags.getClient()); - Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions()); - if (!Invocation.run()) + + llvm::opt::ArgStringList Argv; + for (const std::string &Str : ArrayRef(CommandLine).drop_front()) + Argv.push_back(Str.c_str()); + + auto Invocation = std::make_shared(); + if (!CompilerInvocation::CreateFromArgs(*Invocation, Argv, Diags)) { + // FIXME: Should we just go on like cc1_main does? + return false; + } + + if (!Action.runInvocation(std::move(Invocation), std::move(FS), + PCHContainerOps, Diags.getClient())) return false; std::vector Args = Action.takeLastCC1Arguments(); @@ -988,40 +989,26 @@ bool DependencyScanningWorker::scanDependencies( DependencyConsumer &Consumer, DependencyActionController &Controller, DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr FS, std::optional ModuleName) { - auto FileMgr = - llvm::makeIntrusiveRefCnt(FileSystemOptions{}, FS); - std::vector CCommandLine(CommandLine.size(), nullptr); llvm::transform(CommandLine, CCommandLine.begin(), [](const std::string &Str) { return Str.c_str(); }); auto DiagOpts = CreateAndPopulateDiagOpts(CCommandLine); sanitizeDiagOpts(*DiagOpts); - IntrusiveRefCntPtr Diags = - CompilerInstance::createDiagnostics(FileMgr->getVirtualFileSystem(), - *DiagOpts, &DC, - /*ShouldOwnClient=*/false); - - // Although `Diagnostics` are used only for command-line parsing, the - // custom `DiagConsumer` might expect a `SourceManager` to be present. - SourceManager SrcMgr(*Diags, *FileMgr); - Diags->setSourceManager(&SrcMgr); - // DisableFree is modified by Tooling for running - // in-process; preserve the original value, which is - // always true for a driver invocation. - bool DisableFree = true; + auto Diags = CompilerInstance::createDiagnostics(*FS, *DiagOpts, &DC, + /*ShouldOwnClient=*/false); + DependencyScanningAction Action(Service, WorkingDirectory, Consumer, Controller, DepFS, DepCASFS, CacheFS, - DisableFree, /*EmitDependencyFile=*/false, /*DiagGenerationAsCompilation=*/false, getCASOpts(), ModuleName); bool Success = false; if (CommandLine[1] == "-cc1") { - Success = createAndRunToolInvocation(CommandLine, Action, *FileMgr, + Success = createAndRunToolInvocation(CommandLine, Action, FS, PCHContainerOps, *Diags, Consumer); } else { Success = forEachDriverJob( - CommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) { + CommandLine, *Diags, FS, [&](const driver::Command &Cmd) { if (StringRef(Cmd.getCreator().getName()) != "clang") { // Non-clang command. Just pass through to the dependency // consumer. @@ -1041,7 +1028,7 @@ bool DependencyScanningWorker::scanDependencies( // system to ensure that any file system requests that // are made by the driver do not go through the // dependency scanning filesystem. - return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr, + return createAndRunToolInvocation(std::move(Argv), Action, FS, PCHContainerOps, *Diags, Consumer); }); } @@ -1171,7 +1158,6 @@ void DependencyScanningWorker::computeDependenciesFromCompilerInvocation( // compilation. DependencyScanningAction Action(Service, WorkingDirectory, DepsConsumer, Controller, DepFS, DepCASFS, CacheFS, - /*DisableFree=*/false, /*EmitDependencyFile=*/!DepFile.empty(), DiagGenerationAsCompilation, getCASOpts(), /*ModuleName=*/std::nullopt, VerboseOS); @@ -1179,8 +1165,6 @@ void DependencyScanningWorker::computeDependenciesFromCompilerInvocation( // Ignore result; we're just collecting dependencies. // // FIXME: will clients other than -cc1scand care? - IntrusiveRefCntPtr ActiveFiles = - new FileManager(Invocation->getFileSystemOpts(), BaseFS); - (void)Action.runInvocation(std::move(Invocation), ActiveFiles.get(), + (void)Action.runInvocation(std::move(Invocation), BaseFS, PCHContainerOps, &DiagsConsumer); } From ebe4d188eb36a8f156eebe5888d5f1687b4a3514 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 2 Sep 2025 10:43:04 -0700 Subject: [PATCH 02/41] [clang][analyzer] Delay checking the model-path (#150133) This PR is part of an effort to remove file system usage from the command line parsing code. The reason for that is that it's impossible to do file system access correctly without a configured VFS, and the VFS can only be configured after the command line is parsed. I don't want to intertwine command line parsing and VFS configuration, so I decided to perform the file system access after the command line is parsed and the VFS is configured - ideally right before the file system entity is used for the first time. This patch delays checking that `model-path` is an existing directory. (cherry picked from commit 2e96cd6562f64e11b4b3359f867bab8d45a79672) --- clang/lib/Frontend/CompilerInvocation.cpp | 5 ----- clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp | 11 ++++++++++- clang/test/Analysis/model-file-missing.cpp | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 clang/test/Analysis/model-file-missing.cpp diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 8602b16c2f526..99f9341f017a6 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1377,11 +1377,6 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, if (!AnOpts.CTUDir.empty() && !llvm::sys::fs::is_directory(AnOpts.CTUDir)) Diags->Report(diag::err_analyzer_config_invalid_input) << "ctu-dir" << "a filename"; - - if (!AnOpts.ModelPath.empty() && - !llvm::sys::fs::is_directory(AnOpts.ModelPath)) - Diags->Report(diag::err_analyzer_config_invalid_input) << "model-path" - << "a filename"; } /// Generate a remark argument. This is an inverse of `ParseOptimizationRemark`. diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index 5d392afcb9825..d26c11521e230 100644 --- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -9,6 +9,7 @@ #include "ModelInjector.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/LangStandard.h" #include "clang/Basic/Stack.h" #include "clang/Frontend/ASTUnit.h" @@ -24,7 +25,15 @@ using namespace clang; using namespace ento; -ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) {} +ModelInjector::ModelInjector(CompilerInstance &CI) : CI(CI) { + if (CI.getAnalyzerOpts().ShouldEmitErrorsOnInvalidConfigValue && + !CI.getAnalyzerOpts().ModelPath.empty()) { + auto S = CI.getVirtualFileSystem().status(CI.getAnalyzerOpts().ModelPath); + if (!S || S->getType() != llvm::sys::fs::file_type::directory_file) + CI.getDiagnostics().Report(diag::err_analyzer_config_invalid_input) + << "model-path" << "a filename"; + } +} Stmt *ModelInjector::getBody(const FunctionDecl *D) { onBodySynthesis(D); diff --git a/clang/test/Analysis/model-file-missing.cpp b/clang/test/Analysis/model-file-missing.cpp new file mode 100644 index 0000000000000..c9dfb4ec1b244 --- /dev/null +++ b/clang/test/Analysis/model-file-missing.cpp @@ -0,0 +1,3 @@ +// RUN: not %clang_analyze_cc1 -analyzer-checker=core -analyzer-config model-path=%t/blah %s -o - 2>&1 | FileCheck %s +// CHECK: error: invalid input for analyzer-config option 'model-path', that expects a filename value +// CHECK-NEXT: 1 error generated From fd46f221aa18032512982212dcc52d93614e6fff Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 2 Sep 2025 11:39:26 -0700 Subject: [PATCH 03/41] [clang][analyzer] Delay checking the ctu-dir (#150139) This PR is part of an effort to remove file system usage from the command line parsing code. The reason for that is that it's impossible to do file system access correctly without a configured VFS, and the VFS can only be configured after the command line is parsed. I don't want to intertwine command line parsing and VFS configuration, so I decided to perform the file system access after the command line is parsed and the VFS is configured - ideally right before the file system entity is used for the first time. This patch delays checking that `ctu-dir` is an existing directory. (cherry picked from commit 1fc090f7f1dba97bf0c53d3b158ef4934804d3d9) --- clang/lib/CrossTU/CrossTranslationUnit.cpp | 12 +++++++++++- clang/lib/Frontend/CompilerInvocation.cpp | 4 ---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index 6d0f042d5accd..2e8d56c0d206e 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTImporter.h" #include "clang/AST/Decl.h" #include "clang/AST/ParentMapContext.h" +#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetInfo.h" #include "clang/CrossTU/CrossTUDiagnostic.h" #include "clang/Frontend/ASTUnit.h" @@ -237,7 +238,16 @@ template static bool hasBodyOrInit(const T *D) { } CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI) - : Context(CI.getASTContext()), ASTStorage(CI) {} + : Context(CI.getASTContext()), ASTStorage(CI) { + if (CI.getAnalyzerOpts().ShouldEmitErrorsOnInvalidConfigValue && + !CI.getAnalyzerOpts().CTUDir.empty()) { + auto S = CI.getVirtualFileSystem().status(CI.getAnalyzerOpts().CTUDir); + if (!S || S->getType() != llvm::sys::fs::file_type::directory_file) + CI.getDiagnostics().Report(diag::err_analyzer_config_invalid_input) + << "ctu-dir" + << "a filename"; + } +} CrossTranslationUnitContext::~CrossTranslationUnitContext() {} diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 99f9341f017a6..dfa7ac5dfb1ec 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1373,10 +1373,6 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, if (AnOpts.ShouldTrackConditionsDebug && !AnOpts.ShouldTrackConditions) Diags->Report(diag::err_analyzer_config_invalid_input) << "track-conditions-debug" << "'track-conditions' to also be enabled"; - - if (!AnOpts.CTUDir.empty() && !llvm::sys::fs::is_directory(AnOpts.CTUDir)) - Diags->Report(diag::err_analyzer_config_invalid_input) << "ctu-dir" - << "a filename"; } /// Generate a remark argument. This is an inverse of `ParseOptimizationRemark`. From 64ccaf3fc13f8b53645c956b76dbdb623c1e456b Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 2 Sep 2025 13:04:13 -0700 Subject: [PATCH 04/41] [clang] Delay checking of `-fopenmp-host-ir-file-path` (#150124) This PR is part of an effort to remove file system usage from the command line parsing code. The reason for that is that it's impossible to do file system access correctly without a configured VFS, and the VFS can only be configured after the command line is parsed. I don't want to intertwine command line parsing and VFS configuration, so I decided to perform the file system access after the command line is parsed and the VFS is configured - ideally right before the file system entity is used for the first time. This patch delays opening the OpenMP host IR file until codegen. (cherry picked from commit a24e11fd951d3396ccbb469b2c5dc707dc4196a6) --- clang/include/clang/Basic/DiagnosticDriverKinds.td | 3 --- clang/include/clang/Basic/DiagnosticFrontendKinds.td | 3 +++ clang/include/clang/Driver/Options.td | 3 ++- clang/lib/CodeGen/CodeGenModule.cpp | 5 +++++ clang/lib/Frontend/CompilerInvocation.cpp | 12 ------------ 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index ab66191a3fc0f..b301736b3dbda 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -367,9 +367,6 @@ def err_drv_optimization_remark_format : Error< def err_drv_no_neon_modifier : Error<"[no]neon is not accepted as modifier, please use [no]simd instead">; def err_drv_invalid_omp_target : Error<"OpenMP target is invalid: '%0'">; def err_drv_incompatible_omp_arch : Error<"OpenMP target architecture '%0' pointer size is incompatible with host '%1'">; -def err_drv_omp_host_ir_file_not_found : Error< - "provided host compiler IR file '%0' is required to generate code for OpenMP " - "target regions but cannot be found">; def err_drv_omp_host_target_not_supported : Error< "target '%0' is not a supported OpenMP host target">; def err_drv_ptrauth_not_supported : Error< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index a45500887588a..fac9d81ee542a 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -327,6 +327,9 @@ def err_target_unsupported_type_for_abi : Error<"%0 requires %1 type support, but ABI '%2' does not support it">; } +def err_omp_host_ir_file_not_found : Error< + "provided host compiler IR file '%0' is required to generate code for OpenMP " + "target regions but cannot be found">; def err_alias_to_undefined : Error< "%select{alias|ifunc}0 must point to a defined " "%select{variable or |}1function">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index ab36095da58d4..147552aca2fbe 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -8886,7 +8886,8 @@ def fopenmp_is_target_device : Flag<["-"], "fopenmp-is-target-device">, HelpText<"Generate code only for an OpenMP target device.">; def : Flag<["-"], "fopenmp-is-device">, Alias; def fopenmp_host_ir_file_path : Separate<["-"], "fopenmp-host-ir-file-path">, - HelpText<"Path to the IR file produced by the frontend for the host.">; + HelpText<"Path to the IR file produced by the frontend for the host.">, + MarshallingInfoString>; } // let Visibility = [CC1Option, FC1Option] diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c54c5fe19b974..0806cc4024661 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -588,6 +588,11 @@ void CodeGenModule::createOpenCLRuntime() { } void CodeGenModule::createOpenMPRuntime() { + if (!LangOpts.OMPHostIRFile.empty() && + !llvm::sys::fs::exists(LangOpts.OMPHostIRFile)) + Diags.Report(diag::err_omp_host_ir_file_not_found) + << LangOpts.OMPHostIRFile; + // Select a specialized code generation class based on the target, if any. // If it does not exist use the default implementation. switch (getTriple().getArch()) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index dfa7ac5dfb1ec..fc65b531fd2df 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4264,9 +4264,6 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts, GenerateArg(Consumer, OPT_offload_targets_EQ, Targets); } - if (!Opts.OMPHostIRFile.empty()) - GenerateArg(Consumer, OPT_fopenmp_host_ir_file_path, Opts.OMPHostIRFile); - if (Opts.OpenMPCUDAMode) GenerateArg(Consumer, OPT_fopenmp_cuda_mode); @@ -4892,15 +4889,6 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, } } - // Get OpenMP host file path if any and report if a non existent file is - // found - if (Arg *A = Args.getLastArg(options::OPT_fopenmp_host_ir_file_path)) { - Opts.OMPHostIRFile = A->getValue(); - if (!llvm::sys::fs::exists(Opts.OMPHostIRFile)) - Diags.Report(diag::err_drv_omp_host_ir_file_not_found) - << Opts.OMPHostIRFile; - } - // Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options Opts.OpenMPCUDAMode = Opts.OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN()) && From 311f7f1187d906c301159acea077c3328d244684 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 2 Sep 2025 13:21:38 -0700 Subject: [PATCH 05/41] [flang] Fix build after #150124 (cherry picked from commit b0f85beeefbfdf3eb3f66fed6c5aed13ac423bb4) --- flang/lib/Frontend/CompilerInvocation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index f55d866435997..acb2a4dc0cd5e 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -22,6 +22,7 @@ #include "flang/Tools/TargetSetup.h" #include "flang/Version.inc" #include "clang/Basic/DiagnosticDriver.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/CommonArgs.h" #include "clang/Driver/Driver.h" @@ -1215,7 +1216,7 @@ static bool parseOpenMPArgs(CompilerInvocation &res, llvm::opt::ArgList &args, clang::driver::options::OPT_fopenmp_host_ir_file_path)) { res.getLangOpts().OMPHostIRFile = arg->getValue(); if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile)) - diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found) + diags.Report(clang::diag::err_omp_host_ir_file_not_found) << res.getLangOpts().OMPHostIRFile; } From 36fc81c515024fb31707bd1f3bf9f61bd7718cd1 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 10 Sep 2025 15:29:26 -0700 Subject: [PATCH 06/41] Reland "[clang] Delay normalization of `-fmodules-cache-path` (#150123)" This reverts commit 613caa909c78f707e88960723c6a98364656a926, essentially reapplying 4a4bddec3571d78c8073fa45b57bbabc8796d13d after moving `normalizeModuleCachePath` from clangFrontend to clangLex. This PR is part of an effort to remove file system usage from the command line parsing code. The reason for that is that it's impossible to do file system access correctly without a configured VFS, and the VFS can only be configured after the command line is parsed. I don't want to intertwine command line parsing and VFS configuration, so I decided to perform the file system access after the command line is parsed and the VFS is configured - ideally right before the file system entity is used for the first time. This patch delays normalization of the module cache path until `CompilerInstance` is asked for the cache path in the current compilation context. (cherry picked from commit 55bef46146f05e1911fcb98715716d914efd518c) --- clang/include/clang/Driver/Options.td | 3 ++- clang/include/clang/Lex/HeaderSearch.h | 3 +++ clang/lib/Frontend/CompilerInstance.cpp | 11 ++++++++-- clang/lib/Frontend/CompilerInvocation.cpp | 20 ++----------------- clang/lib/Lex/HeaderSearch.cpp | 7 +++++++ clang/lib/Serialization/ASTWriter.cpp | 7 ++++++- .../DependencyScanningWorker.cpp | 7 ++++--- ...dules-cache-path-canonicalization-output.c | 18 +++++++++++++++++ 8 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 clang/test/Modules/modules-cache-path-canonicalization-output.c diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 147552aca2fbe..20cc72ab9c5dd 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3399,7 +3399,8 @@ defm declspec : BoolOption<"f", "declspec", def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group, Flags<[]>, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, - HelpText<"Specify the module cache path">; + HelpText<"Specify the module cache path">, + MarshallingInfoString>; def fmodules_user_build_path : Separate<["-"], "fmodules-user-build-path">, Group, Flags<[]>, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index bccec4dd951d6..fb95c6187ca74 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -966,6 +966,9 @@ void ApplyHeaderSearchOptions(HeaderSearch &HS, const LangOptions &Lang, const llvm::Triple &triple); +void normalizeModuleCachePath(FileManager &FileMgr, StringRef Path, + SmallVectorImpl &NormalizedPath); + } // namespace clang #endif // LLVM_CLANG_LEX_HEADERSEARCH_H diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 2f25e3f9e8643..e12b8d962310a 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -559,9 +559,16 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { } std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) { + assert(FileMgr && "Specific module cache path requires a FileManager"); + + if (getHeaderSearchOpts().ModuleCachePath.empty()) + return ""; + // Set up the module path, including the hash for the module-creation options. - SmallString<256> SpecificModuleCache(getHeaderSearchOpts().ModuleCachePath); - if (!SpecificModuleCache.empty() && !getHeaderSearchOpts().DisableModuleHash) + SmallString<256> SpecificModuleCache; + normalizeModuleCachePath(*FileMgr, getHeaderSearchOpts().ModuleCachePath, + SpecificModuleCache); + if (!getHeaderSearchOpts().DisableModuleHash) llvm::sys::path::append(SpecificModuleCache, ModuleHash); return std::string(SpecificModuleCache); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index fc65b531fd2df..d197259ee0000 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3577,9 +3577,6 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, if (Opts.UseLibcxx) GenerateArg(Consumer, OPT_stdlib_EQ, "libc++"); - if (!Opts.ModuleCachePath.empty()) - GenerateArg(Consumer, OPT_fmodules_cache_path, Opts.ModuleCachePath); - for (const auto &File : Opts.PrebuiltModuleFiles) GenerateArg(Consumer, OPT_fmodule_file, File.first + "=" + File.second); @@ -3682,8 +3679,7 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, } static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, - DiagnosticsEngine &Diags, - const std::string &WorkingDir) { + DiagnosticsEngine &Diags) { unsigned NumErrorsBefore = Diags.getNumErrors(); HeaderSearchOptions *HeaderSearchOpts = &Opts; @@ -3696,17 +3692,6 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); - // Canonicalize -fmodules-cache-path before storing it. - SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path)); - if (!(P.empty() || llvm::sys::path::is_absolute(P))) { - if (WorkingDir.empty()) - llvm::sys::fs::make_absolute(P); - else - llvm::sys::fs::make_absolute(WorkingDir, P); - } - llvm::sys::path::remove_dots(P); - Opts.ModuleCachePath = std::string(P); - // Only the -fmodule-file== form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); @@ -5561,8 +5546,7 @@ bool CompilerInvocation::CreateFromArgsImpl( InputKind DashX = Res.getFrontendOpts().DashX; ParseTargetArgs(Res.getTargetOpts(), Args, Diags); llvm::Triple T(Res.getTargetOpts().Triple); - ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags, - Res.getFileSystemOpts().WorkingDir); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags); if (Res.getFrontendOpts().GenReducedBMI || Res.getFrontendOpts().ProgramAction == frontend::GenerateReducedModuleInterface || diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 2665580e5afce..bede2c8ead049 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -2095,3 +2095,10 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( } return path::convert_to_slash(Filename); } + +void clang::normalizeModuleCachePath(FileManager &FileMgr, StringRef Path, + SmallVectorImpl &NormalizedPath) { + NormalizedPath.assign(Path.begin(), Path.end()); + FileMgr.makeAbsolutePath(NormalizedPath); + llvm::sys::path::remove_dots(NormalizedPath); +} diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ca1053a44e4d5..c4108dc5c8e68 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -57,6 +57,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/MacroInfo.h" @@ -1731,9 +1732,13 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, StringRef isysroot) { const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + SmallString<256> HSOpts_ModuleCachePath; + normalizeModuleCachePath(PP.getFileManager(), HSOpts.ModuleCachePath, + HSOpts_ModuleCachePath); + AddString(HSOpts.Sysroot, Record); AddString(HSOpts.ResourceDir, Record); - AddString(HSOpts.ModuleCachePath, Record); + AddString(HSOpts_ModuleCachePath, Record); AddString(HSOpts.ModuleUserBuildPath, Record); Record.push_back(HSOpts.DisableModuleHash); Record.push_back(HSOpts.ImplicitModuleMaps); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 5e0b5df50fe57..0a2be1518131e 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -606,9 +606,10 @@ class DependencyScanningAction { // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { - StringRef ModulesCachePath = - ScanInstance.getHeaderSearchOpts().ModuleCachePath; - + SmallString<256> ModulesCachePath; + normalizeModuleCachePath( + *FileMgr, ScanInstance.getHeaderSearchOpts().ModuleCachePath, + ModulesCachePath); DepFS->resetBypassedPathPrefix(); if (!ModulesCachePath.empty()) DepFS->setBypassedPathPrefix(ModulesCachePath); diff --git a/clang/test/Modules/modules-cache-path-canonicalization-output.c b/clang/test/Modules/modules-cache-path-canonicalization-output.c new file mode 100644 index 0000000000000..ad71b69e5299e --- /dev/null +++ b/clang/test/Modules/modules-cache-path-canonicalization-output.c @@ -0,0 +1,18 @@ +// This checks that implicitly-built modules produce identical PCM +// files regardless of the spelling of the same module cache path. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fsyntax-only %t/tu.c \ +// RUN: -fmodules-cache-path=%t/cache -fdisable-module-hash +// RUN: mv %t/cache/M.pcm %t/M.pcm +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fsyntax-only %t/tu.c \ +// RUN: -fmodules-cache-path=%t/./cache -fdisable-module-hash +// RUN: diff %t/./cache/M.pcm %t/M.pcm + +//--- tu.c +#include "M.h" +//--- M.h +//--- module.modulemap +module M { header "M.h" } From d53f86e0722e2fd9a53a854adb7430f7629b2ed9 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 11 Sep 2025 09:08:47 -0700 Subject: [PATCH 07/41] [clang] Use VFS for `-fopenmp-host-ir-file-path` (#156727) This is a follow-up to #150124. This PR makes it so that the `-fopenmp-host-ir-file-path` respects VFS overlays, like any other input file. (cherry picked from commit d1c0b1b6203d4005ad9a1baefe843ab45b3693a8) --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 3 +- clang/lib/CodeGen/CodeGenModule.cpp | 3 +- clang/test/OpenMP/host-ir-file-vfs.c | 33 +++++++++++++++++++ .../llvm/Frontend/OpenMP/OMPIRBuilder.h | 7 +++- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp | 6 ++-- .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 5 ++- 6 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 clang/test/OpenMP/host-ir-file-vfs.c diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index a5f2f0efa2c3b..c6b5620c40b84 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1038,7 +1038,8 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM) /*HasRequiresReverseOffload*/ false, /*HasRequiresUnifiedAddress*/ false, hasRequiresUnifiedSharedMemory(), /*HasRequiresDynamicAllocators*/ false); OMPBuilder.initialize(); - OMPBuilder.loadOffloadInfoMetadata(CGM.getLangOpts().OpenMPIsTargetDevice + OMPBuilder.loadOffloadInfoMetadata(*CGM.getFileSystem(), + CGM.getLangOpts().OpenMPIsTargetDevice ? CGM.getLangOpts().OMPHostIRFile : StringRef{}); OMPBuilder.setConfig(Config); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0806cc4024661..276752150fea1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -588,8 +588,7 @@ void CodeGenModule::createOpenCLRuntime() { } void CodeGenModule::createOpenMPRuntime() { - if (!LangOpts.OMPHostIRFile.empty() && - !llvm::sys::fs::exists(LangOpts.OMPHostIRFile)) + if (!LangOpts.OMPHostIRFile.empty() && !FS->exists(LangOpts.OMPHostIRFile)) Diags.Report(diag::err_omp_host_ir_file_not_found) << LangOpts.OMPHostIRFile; diff --git a/clang/test/OpenMP/host-ir-file-vfs.c b/clang/test/OpenMP/host-ir-file-vfs.c new file mode 100644 index 0000000000000..394d8fbcc94ac --- /dev/null +++ b/clang/test/OpenMP/host-ir-file-vfs.c @@ -0,0 +1,33 @@ +// This test checks that the OpenMP host IR file goes through VFS overlays. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: sed -e "s|DIR|%/t|g" %t/vfs.json.in > %t/vfs.json +// RUN: %clang_cc1 -fopenmp-simd -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm-bc %t/host.c -o %t/host.bc + +// RUN: %clang_cc1 -fopenmp-simd -triple i386-unknown-unknown -fopenmp-targets=i386-pc-linux-gnu -emit-llvm %t/device.c -o - \ +// RUN: -fopenmp-is-target-device -fopenmp-host-ir-file-path %t/virtual/host.bc -ivfsoverlay %t/vfs.json -verify + +//--- vfs.json.in +{ + 'version': 0, + 'use-external-names': true, + 'roots': [ + { + 'name': 'DIR/virtual', + 'type': 'directory', + 'contents': [ + { + 'name': 'host.bc', + 'type': 'file', + 'external-contents': 'DIR/host.bc' + } + ] + } + ] +} + +//--- host.c +//--- device.c +// expected-no-diagnostics diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h index 206ad4a4ef85f..584af21049908 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -38,6 +38,10 @@ class Loop; class LoopAnalysis; class LoopInfo; +namespace vfs { +class FileSystem; +} // namespace vfs + /// Move the instruction after an InsertPoint to the beginning of another /// BasicBlock. /// @@ -3491,7 +3495,8 @@ class OpenMPIRBuilder { /// \param HostFilePath The path to the host IR file, /// used to load in offload metadata for the device, allowing host and device /// to maintain the same metadata mapping. - LLVM_ABI void loadOffloadInfoMetadata(StringRef HostFilePath); + LLVM_ABI void loadOffloadInfoMetadata(vfs::FileSystem &VFS, + StringRef HostFilePath); /// Gets (if variable with the given name already exist) or creates /// internal global variable with the specified Name. The created variable has diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 840ca8364e218..39862335198c7 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -51,6 +51,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -10083,11 +10084,12 @@ void OpenMPIRBuilder::loadOffloadInfoMetadata(Module &M) { } } -void OpenMPIRBuilder::loadOffloadInfoMetadata(StringRef HostFilePath) { +void OpenMPIRBuilder::loadOffloadInfoMetadata(vfs::FileSystem &VFS, + StringRef HostFilePath) { if (HostFilePath.empty()) return; - auto Buf = MemoryBuffer::getFile(HostFilePath); + auto Buf = VFS.getBufferForFile(HostFilePath); if (std::error_code Err = Buf.getError()) { report_fatal_error(("error opening host file from host file path inside of " "OpenMPIRBuilder: " + diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index f8ea6ee07447b..0dbe28f991b3c 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -36,6 +36,7 @@ #include "llvm/IR/MDBuilder.h" #include "llvm/IR/ReplaceConstant.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -6185,7 +6186,9 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::amendOperation( if (auto filepathAttr = dyn_cast(attr)) { llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); - ompBuilder->loadOffloadInfoMetadata(filepathAttr.getValue()); + auto VFS = llvm::vfs::getRealFileSystem(); + ompBuilder->loadOffloadInfoMetadata(*VFS, + filepathAttr.getValue()); return success(); } return failure(); From 36d7fc131f74f1a016f66058b574e773e3fe61f2 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 15 Sep 2025 09:37:19 -0700 Subject: [PATCH 08/41] [clang] Avoid reparsing VFS overlay files for module dep collector (#158372) This PR uses the new-ish `llvm::vfs::FileSystem::visit()` interface to collect VFS overlay entries from an existing `FileSystem` instance rather than parsing the VFS YAML file anew. This prevents duplicate diagnostics as observed by `clang/test/VFS/broken-vfs-module-dep.c`. (cherry picked from commit 4957c473bc73a3a0bf1037adec770547c4a0aa02) --- clang/lib/Frontend/CompilerInstance.cpp | 15 ++++----------- clang/test/VFS/broken-vfs-module-dep.c | 1 - llvm/include/llvm/Support/VirtualFileSystem.h | 10 +++------- llvm/lib/Support/VirtualFileSystem.cpp | 16 +++------------- 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index e12b8d962310a..c219449234717 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -276,19 +276,12 @@ static void collectIncludePCH(CompilerInstance &CI, static void collectVFSEntries(CompilerInstance &CI, std::shared_ptr MDC) { - if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) - return; - // Collect all VFS found. SmallVector VFSEntries; - for (const std::string &VFSFile : CI.getHeaderSearchOpts().VFSOverlayFiles) { - llvm::ErrorOr> Buffer = - llvm::MemoryBuffer::getFile(VFSFile); - if (!Buffer) - return; - llvm::vfs::collectVFSFromYAML(std::move(Buffer.get()), - /*DiagHandler*/ nullptr, VFSFile, VFSEntries); - } + CI.getVirtualFileSystem().visit([&](llvm::vfs::FileSystem &VFS) { + if (auto *RedirectingVFS = dyn_cast(&VFS)) + llvm::vfs::collectVFSEntries(*RedirectingVFS, VFSEntries); + }); for (auto &E : VFSEntries) MDC->addFile(E.VPath, E.RPath); diff --git a/clang/test/VFS/broken-vfs-module-dep.c b/clang/test/VFS/broken-vfs-module-dep.c index 2336306de8c6d..1c371a13e85c9 100644 --- a/clang/test/VFS/broken-vfs-module-dep.c +++ b/clang/test/VFS/broken-vfs-module-dep.c @@ -2,6 +2,5 @@ // RUN: mkdir -p %t // RUN: not %clang_cc1 -module-dependency-dir %t -ivfsoverlay %S/Inputs/invalid-yaml.yaml %s 2>&1 | FileCheck %s -// CHECK: error: Unexpected token // CHECK: error: Unexpected token // CHECK: 1 error generated diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index 0b94f5b5f34a5..2dd696faaba48 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -1178,14 +1178,10 @@ class LLVM_ABI RedirectingFileSystem }; /// Collect all pairs of entries from the -/// \p YAMLFilePath. This is used by the module dependency collector to forward +/// \p VFS. This is used by the module dependency collector to forward /// the entries into the reproducer output VFS YAML file. -LLVM_ABI void collectVFSFromYAML( - std::unique_ptr Buffer, - llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, - SmallVectorImpl &CollectedEntries, - void *DiagContext = nullptr, - IntrusiveRefCntPtr ExternalFS = getRealFileSystem()); +void collectVFSEntries(RedirectingFileSystem &VFS, + SmallVectorImpl &CollectedEntries); class YAMLVFSWriter { std::vector Mappings; diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index da5e74867a598..afcfcc7d3f4c3 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -2726,19 +2726,9 @@ static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath())); } -void vfs::collectVFSFromYAML(std::unique_ptr Buffer, - SourceMgr::DiagHandlerTy DiagHandler, - StringRef YAMLFilePath, - SmallVectorImpl &CollectedEntries, - void *DiagContext, - IntrusiveRefCntPtr ExternalFS) { - std::unique_ptr VFS = RedirectingFileSystem::create( - std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext, - std::move(ExternalFS)); - if (!VFS) - return; - ErrorOr RootResult = - VFS->lookupPath("/"); +void vfs::collectVFSEntries(RedirectingFileSystem &VFS, + SmallVectorImpl &CollectedEntries) { + ErrorOr RootResult = VFS.lookupPath("/"); if (!RootResult) return; SmallVector Components; From 55d878607951b1ca802f1d3517411e6c0f047068 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 15 Sep 2025 14:30:13 -0700 Subject: [PATCH 09/41] [clang] Don't fail `ExecuteCompilerInvocation()` due to caller errors (#158695) This PR changes the behavior of `clang::ExecuteCompilerInvocation()` so that it only returns early when the `DiagnosticsEngine` emitted errors **within** the function. Handling errors emitted before the function got called is a responsibility of the caller. Necessary for #158381. (cherry picked from commit f33fb0d7b2af203c42d0e7096b29560dda3e71ce) --- clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index a084b883e1b6a..3a8f0d8dd8545 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -214,6 +214,8 @@ CreateFrontendAction(CompilerInstance &CI) { } bool ExecuteCompilerInvocation(CompilerInstance *Clang) { + unsigned NumErrorsBefore = Clang->getDiagnostics().getNumErrors(); + // Honor -help. if (Clang->getFrontendOpts().ShowHelp) { driver::getDriverOptTable().printHelp( @@ -309,9 +311,12 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { } #endif - // If there were errors in processing arguments, don't do anything else. - if (Clang->getDiagnostics().hasErrorOccurred()) + // If there were errors in the above, don't do anything else. + // This intentionally ignores errors emitted before this function to + // accommodate lenient callers that decided to make progress despite errors. + if (Clang->getDiagnostics().getNumErrors() != NumErrorsBefore) return false; + // Create and execute the frontend action. std::unique_ptr Act(CreateFrontendAction(*Clang)); if (!Act) From 7fd9a1085869dad295145f5a6ec5070d7fd01855 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 18 Sep 2025 10:51:21 -0700 Subject: [PATCH 10/41] [clang] Only set non-empty bypass to scan VFS (#159605) Normalizing an empty modules cache path results in an incorrect non-empty path (the working directory). This PR conditionalizes more code to avoid this. Tested downstream by swift/llvm-project and the `DependencyScanningCAPITests.DependencyScanningFSCacheOutOfDate` unit test. (cherry picked from commit 5a339b074e625a7e9c92ae98b93a2bb5e1ae9524) --- .../DependencyScanning/DependencyScanningWorker.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 0a2be1518131e..650a3d139b92d 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -606,13 +606,14 @@ class DependencyScanningAction { // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { - SmallString<256> ModulesCachePath; - normalizeModuleCachePath( - *FileMgr, ScanInstance.getHeaderSearchOpts().ModuleCachePath, - ModulesCachePath); DepFS->resetBypassedPathPrefix(); - if (!ModulesCachePath.empty()) + if (!ScanInstance.getHeaderSearchOpts().ModuleCachePath.empty()) { + SmallString<256> ModulesCachePath; + normalizeModuleCachePath( + *FileMgr, ScanInstance.getHeaderSearchOpts().ModuleCachePath, + ModulesCachePath); DepFS->setBypassedPathPrefix(ModulesCachePath); + } ScanInstance.setDependencyDirectivesGetter( std::make_unique(*FileMgr)); From 471dd1647b800e70ac4966430a3076b00aef4a2a Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 17 Sep 2025 09:15:46 -0700 Subject: [PATCH 11/41] Merge commit '30633f308941' from llvm.org/main into next (cherry picked from commit 95ea104fb4034a99b51750c067121420a4e5a728) --- .../clang-include-fixer/IncludeFixer.cpp | 3 +- clang-tools-extra/clangd/Compiler.cpp | 10 ++-- .../include-cleaner/unittests/RecordTest.cpp | 5 +- .../include/clang/Frontend/CompilerInstance.h | 45 ++++++++++++---- .../clang/Frontend/CompilerInvocation.h | 3 +- clang/lib/Frontend/ASTUnit.cpp | 10 ++-- clang/lib/Frontend/ChainedIncludesSource.cpp | 1 + clang/lib/Frontend/CompileJobCache.cpp | 2 +- clang/lib/Frontend/CompilerInstance.cpp | 54 ++++++++++--------- clang/lib/Frontend/CompilerInvocation.cpp | 23 +++++--- clang/lib/Frontend/FrontendAction.cpp | 5 +- clang/lib/Frontend/PrecompiledPreamble.cpp | 5 +- .../lib/Frontend/Rewrite/FrontendActions.cpp | 2 +- clang/lib/Interpreter/Interpreter.cpp | 7 ++- .../StaticAnalyzer/Frontend/ModelInjector.cpp | 2 +- clang/lib/Testing/TestAST.cpp | 10 ++-- .../DependencyScanningWorker.cpp | 12 ++--- clang/lib/Tooling/Tooling.cpp | 3 +- .../clang-import-test/clang-import-test.cpp | 4 +- .../clang-installapi/ClangInstallAPI.cpp | 2 +- clang/tools/driver/cc1_main.cpp | 8 +-- clang/unittests/AST/ExternalASTSourceTest.cpp | 3 +- clang/unittests/CodeGen/TestCompiler.h | 3 +- clang/unittests/Driver/ToolChainTest.cpp | 3 +- .../unittests/Frontend/CodeGenActionTest.cpp | 6 ++- .../Frontend/CompilerInstanceTest.cpp | 4 +- .../unittests/Frontend/FrontendActionTest.cpp | 19 ++++--- clang/unittests/Frontend/OutputStreamTest.cpp | 9 ++-- .../Serialization/ForceCheckFileInputTest.cpp | 9 ++-- .../Serialization/ModuleCacheTest.cpp | 4 ++ .../Serialization/NoCommentsTest.cpp | 1 + .../PreambleInNamedModulesTest.cpp | 8 +-- clang/unittests/Support/TimeProfilerTest.cpp | 7 ++- .../DependencyScannerTest.cpp | 3 +- lldb/source/Commands/CommandObjectTarget.cpp | 4 +- .../Clang/ClangExpressionParser.cpp | 6 ++- .../Clang/ClangModulesDeclVendor.cpp | 3 +- 37 files changed, 185 insertions(+), 123 deletions(-) diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp index 7b0e4ecda8214..a638fb6bbad0e 100644 --- a/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp +++ b/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp @@ -94,8 +94,7 @@ bool IncludeFixerActionFactory::runInvocation( // Create the compiler's actual diagnostics engine. We want to drop all // diagnostics here. - Compiler.createDiagnostics(Files->getVirtualFileSystem(), - new clang::IgnoringDiagConsumer, + Compiler.createDiagnostics(new clang::IgnoringDiagConsumer, /*ShouldOwnClient=*/true); Compiler.createSourceManager(*Files); diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 8b3865c8a8e5c..6ebc2eac25745 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -147,13 +147,9 @@ prepareCompilerInstance(std::unique_ptr CI, } auto Clang = std::make_unique(std::move(CI)); - Clang->createDiagnostics(*VFS, &DiagsClient, false); - - if (auto VFSWithRemapping = createVFSFromCompilerInvocation( - Clang->getInvocation(), Clang->getDiagnostics(), VFS)) - VFS = VFSWithRemapping; - Clang->createFileManager(VFS); - + Clang->createVirtualFileSystem(VFS, &DiagsClient); + Clang->createDiagnostics(&DiagsClient, false); + Clang->createFileManager(); if (!Clang->createTarget()) return nullptr; diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp index 91d2697712b6e..a09ba01fb678c 100644 --- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp @@ -625,9 +625,10 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) { *Diags, "clang")); auto Clang = std::make_unique(std::move(Invocation)); - Clang->createDiagnostics(*VFS); + Clang->createVirtualFileSystem(VFS); + Clang->createDiagnostics(); - auto *FM = Clang->createFileManager(VFS); + auto *FM = Clang->createFileManager(); ASSERT_TRUE(Clang->ExecuteAction(*Inputs.MakeAction())); EXPECT_THAT( PI.getExporters(llvm::cantFail(FM->getFileRef("foo.h")), *FM), diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 72861e573ea34..3fed94a024e53 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -87,6 +87,9 @@ class CompilerInstance : public ModuleLoader { /// The options used in this compiler instance. std::shared_ptr Invocation; + /// The virtual file system instance. + IntrusiveRefCntPtr VFS; + /// The diagnostics engine instance. IntrusiveRefCntPtr Diagnostics; @@ -453,7 +456,31 @@ class CompilerInstance : public ModuleLoader { /// @name Virtual File System /// @{ - llvm::vfs::FileSystem &getVirtualFileSystem() const; + bool hasVirtualFileSystem() const { return VFS != nullptr; } + + /// Create a virtual file system instance based on the invocation. + /// + /// @param BaseFS The file system that may be used when configuring the final + /// file system, and act as the underlying file system. Must not + /// be NULL. + /// @param DC If non-NULL, the diagnostic consumer to be used in case + /// configuring the file system emits diagnostics. Note that the + /// DiagnosticsEngine using the consumer won't obey the + /// --warning-suppression-mappings= flag. + void createVirtualFileSystem(IntrusiveRefCntPtr + BaseFS = llvm::vfs::getRealFileSystem(), + DiagnosticConsumer *DC = nullptr); + + /// Use the given file system. + void setVirtualFileSystem(IntrusiveRefCntPtr FS) { + VFS = std::move(FS); + } + + llvm::vfs::FileSystem &getVirtualFileSystem() const { return *VFS; } + + IntrusiveRefCntPtr getVirtualFileSystemPtr() const { + return VFS; + } /// @} /// @name File Manager @@ -691,32 +718,31 @@ class CompilerInstance : public ModuleLoader { /// Note that this routine also replaces the diagnostic client, /// allocating one if one is not provided. /// - /// \param VFS is used for any IO needed when creating DiagnosticsEngine. It - /// doesn't replace VFS in the CompilerInstance (if any). - /// /// \param Client If non-NULL, a diagnostic client that will be /// attached to (and, then, owned by) the DiagnosticsEngine inside this AST /// unit. /// /// \param ShouldOwnClient If Client is non-NULL, specifies whether /// the diagnostic object should take ownership of the client. - void createDiagnostics(llvm::vfs::FileSystem &VFS, - DiagnosticConsumer *Client = nullptr, + void createDiagnostics(DiagnosticConsumer *Client = nullptr, bool ShouldOwnClient = true); - /// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter. + /// Create a DiagnosticsEngine object. /// /// If no diagnostic client is provided, this creates a /// DiagnosticConsumer that is owned by the returned diagnostic /// object, if using directly the caller is responsible for /// releasing the returned DiagnosticsEngine's client eventually. /// + /// \param VFS The file system used to load the suppression mappings file. + /// /// \param Opts - The diagnostic options; note that the created text /// diagnostic object contains a reference to these options. /// /// \param Client If non-NULL, a diagnostic client that will be /// attached to (and, then, owned by) the returned DiagnosticsEngine - /// object. + /// object. If NULL, the returned DiagnosticsEngine will own a newly-created + /// client. /// /// \param CodeGenOpts If non-NULL, the code gen options in use, which may be /// used by some diagnostics printers (for logging purposes only). @@ -731,8 +757,7 @@ class CompilerInstance : public ModuleLoader { /// Create the file manager and replace any existing one with it. /// /// \return The new file manager on success, or null on failure. - FileManager * - createFileManager(IntrusiveRefCntPtr VFS = nullptr); + FileManager *createFileManager(); /// Create the source manager and replace any existing one with it. void createSourceManager(FileManager &FileMgr); diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 4bf5f8ec15b86..d3455d240d916 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -434,7 +434,8 @@ IntrusiveRefCntPtr createVFSFromCompilerInvocation( IntrusiveRefCntPtr createVFSFromCompilerInvocation( const CompilerInvocation &CI, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr BaseFS); + IntrusiveRefCntPtr BaseFS, + std::shared_ptr OverrideCAS = nullptr); IntrusiveRefCntPtr createVFSFromOverlayFiles(ArrayRef VFSOverlayFiles, diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index a99e176291582..d756fd738b6a3 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1179,10 +1179,14 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, // Ensure that Clang has a FileManager with the right VFS, which may have // changed above in AddImplicitPreamble. If VFS is nullptr, rely on // createFileManager to create one. - if (VFS && FileMgr && &FileMgr->getVirtualFileSystem() == VFS) + if (VFS && FileMgr && &FileMgr->getVirtualFileSystem() == VFS) { + Clang->setVirtualFileSystem(std::move(VFS)); Clang->setFileManager(&*FileMgr); - else - FileMgr = Clang->createFileManager(std::move(VFS)); + } else { + Clang->setVirtualFileSystem(std::move(VFS)); + Clang->createFileManager(); + FileMgr = Clang->getFileManagerPtr().get(); + } // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp index f9a398dbfb90f..b6631d3eb9567 100644 --- a/clang/lib/Frontend/ChainedIncludesSource.cpp +++ b/clang/lib/Frontend/ChainedIncludesSource.cpp @@ -124,6 +124,7 @@ IntrusiveRefCntPtr clang::createChainedIncludesSource( auto Clang = std::make_unique( std::move(CInvok), CI.getPCHContainerOperations()); + Clang->createVirtualFileSystem(); Clang->setDiagnostics(Diags.get()); Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts())); diff --git a/clang/lib/Frontend/CompileJobCache.cpp b/clang/lib/Frontend/CompileJobCache.cpp index 6e32eb80edb87..4d0355da01351 100644 --- a/clang/lib/Frontend/CompileJobCache.cpp +++ b/clang/lib/Frontend/CompileJobCache.cpp @@ -613,8 +613,8 @@ Expected> CompileJobCache::replayCachedResult( std::optional *OutMCOutputID) { CompilerInstance Clang(std::move(Invok)); llvm::raw_svector_ostream DiagOS(DiagText); + Clang.createVirtualFileSystem(llvm::vfs::getRealFileSystem()); Clang.createDiagnostics( - *llvm::vfs::getRealFileSystem(), new TextDiagnosticPrinter(DiagOS, Clang.getDiagnosticOpts())); Clang.setVerboseOutputStream(DiagOS); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index c219449234717..75dfd40b09ee9 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -172,11 +172,11 @@ bool CompilerInstance::createTarget() { return true; } -llvm::vfs::FileSystem &CompilerInstance::getVirtualFileSystem() const { - return getFileManager().getVirtualFileSystem(); -} - void CompilerInstance::setFileManager(FileManager *Value) { + if (!hasVirtualFileSystem()) + setVirtualFileSystem(Value->getVirtualFileSystemPtr()); + assert(Value == nullptr || + getVirtualFileSystemPtr() == Value->getVirtualFileSystemPtr()); FileMgr = Value; } @@ -287,6 +287,20 @@ static void collectVFSEntries(CompilerInstance &CI, MDC->addFile(E.VPath, E.RPath); } +void CompilerInstance::createVirtualFileSystem( + IntrusiveRefCntPtr BaseFS, DiagnosticConsumer *DC) { + DiagnosticOptions DiagOpts; + DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts, DC, + /*ShouldOwnClient=*/false); + + VFS = createVFSFromCompilerInvocation(getInvocation(), Diags, + std::move(BaseFS), CAS); + // FIXME: Should this go into createVFSFromCompilerInvocation? + if (getFrontendOpts().ShowStats) + VFS = + llvm::makeIntrusiveRefCnt(std::move(VFS)); +} + // Diagnostics static void SetUpDiagnosticLog(DiagnosticOptions &DiagOpts, const CodeGenOptions *CodeGenOpts, @@ -338,11 +352,10 @@ static void SetupSerializedDiagnostics(DiagnosticOptions &DiagOpts, } } -void CompilerInstance::createDiagnostics(llvm::vfs::FileSystem &VFS, - DiagnosticConsumer *Client, +void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client, bool ShouldOwnClient) { - Diagnostics = createDiagnostics(VFS, getDiagnosticOpts(), Client, - ShouldOwnClient, &getCodeGenOpts()); + Diagnostics = createDiagnostics(getVirtualFileSystem(), getDiagnosticOpts(), + Client, ShouldOwnClient, &getCodeGenOpts()); } IntrusiveRefCntPtr CompilerInstance::createDiagnostics( @@ -381,17 +394,9 @@ IntrusiveRefCntPtr CompilerInstance::createDiagnostics( // File Manager -FileManager *CompilerInstance::createFileManager( - IntrusiveRefCntPtr VFS) { - if (!VFS) - VFS = FileMgr ? &FileMgr->getVirtualFileSystem() - : createVFSFromCompilerInvocation(getInvocation(), - getDiagnostics(), CAS); - assert(VFS && "FileManager has no VFS?"); - if (getFrontendOpts().ShowStats) - VFS = - llvm::makeIntrusiveRefCnt(std::move(VFS)); - FileMgr = new FileManager(getFileSystemOpts(), std::move(VFS)); +FileManager *CompilerInstance::createFileManager() { + assert(VFS && "CompilerInstance needs a VFS for creating FileManager"); + FileMgr = llvm::makeIntrusiveRefCnt(getFileSystemOpts(), VFS); return FileMgr.get(); } @@ -1388,20 +1393,21 @@ std::unique_ptr CompilerInstance::cloneForModuleCompileImpl( auto &Inv = Instance.getInvocation(); if (ThreadSafeConfig) { - Instance.createFileManager(ThreadSafeConfig->getVFS()); + Instance.setVirtualFileSystem(ThreadSafeConfig->getVFS()); + Instance.createFileManager(); } else if (FrontendOpts.ModulesShareFileManager) { + Instance.setVirtualFileSystem(getVirtualFileSystemPtr()); Instance.setFileManager(&getFileManager()); } else { - Instance.createFileManager(&getVirtualFileSystem()); + Instance.setVirtualFileSystem(&getVirtualFileSystem()); + Instance.createFileManager(); } if (ThreadSafeConfig) { - Instance.createDiagnostics(Instance.getVirtualFileSystem(), - &ThreadSafeConfig->getDiagConsumer(), + Instance.createDiagnostics(&ThreadSafeConfig->getDiagConsumer(), /*ShouldOwnClient=*/false); } else { Instance.createDiagnostics( - Instance.getVirtualFileSystem(), new ForwardingDiagnosticConsumer(getDiagnosticClient()), /*ShouldOwnClient=*/true); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index d197259ee0000..95a7a46748722 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1527,9 +1527,13 @@ static std::string serializeXRayInstrumentationBundle(const XRayInstrSet &S) { static IntrusiveRefCntPtr createBaseFS(const FileSystemOptions &FSOpts, const FrontendOptions &FEOpts, const CASOptions &CASOpts, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr BaseFS, std::shared_ptr OverrideCAS) { + if (!OverrideCAS) + return BaseFS; + if (FSOpts.CASFileSystemRootID.empty() && FEOpts.CASIncludeTreeID.empty()) - return llvm::vfs::getRealFileSystem(); + return BaseFS; // If no CAS was provided, create one with CASOptions. std::shared_ptr CAS = std::move(OverrideCAS); @@ -2214,7 +2218,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } if (!Opts.ProfileInstrumentUsePath.empty()) { - auto FS = createBaseFS(FSOpts, FEOpts, CASOpts, Diags, nullptr); + auto FS = createBaseFS(FSOpts, FEOpts, CASOpts, Diags, + llvm::vfs::getRealFileSystem(), nullptr); setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath, *FS, Diags); } @@ -5880,17 +5885,19 @@ clang::createVFSFromCompilerInvocation( const CompilerInvocation &CI, DiagnosticsEngine &Diags, std::shared_ptr OverrideCAS) { return createVFSFromCompilerInvocation( - CI, Diags, - createBaseFS(CI.getFileSystemOpts(), CI.getFrontendOpts(), - CI.getCASOpts(), Diags, std::move(OverrideCAS))); + CI, Diags, llvm::vfs::getRealFileSystem(), std::move(OverrideCAS)); } IntrusiveRefCntPtr clang::createVFSFromCompilerInvocation( const CompilerInvocation &CI, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr BaseFS) { - return createVFSFromOverlayFiles(CI.getHeaderSearchOpts().VFSOverlayFiles, - Diags, std::move(BaseFS)); + IntrusiveRefCntPtr BaseFS, + std::shared_ptr OverrideCAS) { + return createVFSFromOverlayFiles( + CI.getHeaderSearchOpts().VFSOverlayFiles, Diags, + createBaseFS(CI.getFileSystemOpts(), CI.getFrontendOpts(), + CI.getCASOpts(), Diags, std::move(BaseFS), + std::move(OverrideCAS))); } IntrusiveRefCntPtr clang::createVFSFromOverlayFiles( diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 269dba1745d73..3c7c9772d2fdd 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -916,6 +916,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. + CI.setVirtualFileSystem(AST->getFileManager().getVirtualFileSystemPtr()); CI.setFileManager(&AST->getFileManager()); CI.createSourceManager(CI.getFileManager()); CI.getSourceManager().initializeForReplay(AST->getSourceManager()); @@ -1006,7 +1007,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, return true; } - // Set up the file and source managers, if needed. + // Set up the file system, file and source managers, if needed. + if (!CI.hasVirtualFileSystem()) + CI.createVirtualFileSystem(); if (!CI.hasFileManager()) { if (!CI.createFileManager()) { return false; diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index 3f3fe3c9937e4..efa6d11a6f1d2 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -479,11 +479,10 @@ llvm::ErrorOr PrecompiledPreamble::Build( Diagnostics.Reset(); ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts(), *VFS); - VFS = - createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS); + Clang->createVirtualFileSystem(VFS, Diagnostics.getClient()); // Create a file manager object to provide access to and cache the filesystem. - Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); + Clang->createFileManager(); // Create the source manager. Clang->setSourceManager( diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 9d82af8ac7f91..e47aa4eba4f0e 100644 --- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -250,8 +250,8 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener { CompilerInstance Instance( std::make_shared(CI.getInvocation()), CI.getPCHContainerOperations(), &CI.getModuleCache()); + Instance.setVirtualFileSystem(CI.getVirtualFileSystemPtr()); Instance.createDiagnostics( - CI.getVirtualFileSystem(), new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), /*ShouldOwnClient=*/true); Instance.getFrontendOpts().DisableFree = false; diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index ed3bae59a144c..030a7ace92c31 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -108,8 +108,10 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { Clang->getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(Argv[0], nullptr); + Clang->createVirtualFileSystem(); + // Create the actual diagnostics engine. - Clang->createDiagnostics(*llvm::vfs::getRealFileSystem()); + Clang->createDiagnostics(); if (!Clang->hasDiagnostics()) return llvm::createStringError(llvm::errc::not_supported, "Initialization failed. " @@ -489,7 +491,8 @@ Interpreter::createWithCUDA(std::unique_ptr CI, std::make_unique( llvm::vfs::getRealFileSystem()); OverlayVFS->pushOverlay(IMVFS); - CI->createFileManager(OverlayVFS); + CI->createVirtualFileSystem(OverlayVFS); + CI->createFileManager(); llvm::Expected> InterpOrErr = Interpreter::create(std::move(CI)); diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index d26c11521e230..51e23a3b4ac6a 100644 --- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -84,8 +84,8 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { // behavior for models CompilerInstance Instance(std::move(Invocation), CI.getPCHContainerOperations()); + Instance.setVirtualFileSystem(CI.getVirtualFileSystemPtr()); Instance.createDiagnostics( - CI.getVirtualFileSystem(), new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), /*ShouldOwnClient=*/true); diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp index b59a8d55129de..9ad0de95530fb 100644 --- a/clang/lib/Testing/TestAST.cpp +++ b/clang/lib/Testing/TestAST.cpp @@ -54,8 +54,10 @@ class StoreDiagnostics : public DiagnosticConsumer { // Fills in the bits of a CompilerInstance that weren't initialized yet. // Provides "empty" ASTContext etc if we fail before parsing gets started. void createMissingComponents(CompilerInstance &Clang) { + if (!Clang.hasVirtualFileSystem()) + Clang.createVirtualFileSystem(); if (!Clang.hasDiagnostics()) - Clang.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Clang.createDiagnostics(); if (!Clang.hasFileManager()) Clang.createFileManager(); if (!Clang.hasSourceManager()) @@ -98,7 +100,9 @@ TestAST::TestAST(const TestInputs &In) { // Extra error conditions are reported through diagnostics, set that up first. bool ErrorOK = In.ErrorOK || llvm::StringRef(In.Code).contains("error-ok"); - Clang->createDiagnostics(*VFS, new StoreDiagnostics(Diagnostics, !ErrorOK)); + auto DiagConsumer = new StoreDiagnostics(Diagnostics, !ErrorOK); + Clang->createVirtualFileSystem(std::move(VFS), DiagConsumer); + Clang->createDiagnostics(DiagConsumer); // Parse cc1 argv, (typically [-std=c++20 input.cc]) into CompilerInvocation. std::vector Argv; @@ -115,7 +119,7 @@ TestAST::TestAST(const TestInputs &In) { } assert(!Clang->getInvocation().getFrontendOpts().DisableFree); - Clang->createFileManager(VFS); + Clang->createFileManager(); // Running the FrontendAction creates the other components: SourceManager, // Preprocessor, ASTContext, Sema. Preprocessor needs TargetInfo to be set. diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 650a3d139b92d..7c74b9c7decfd 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -566,12 +566,13 @@ class DependencyScanningAction { ScanInstance.getInvocation().getCASOpts() = CASOpts; ScanInstance.setBuildingModule(false); + ScanInstance.createVirtualFileSystem(FS, DiagConsumer); + // Create the compiler's actual diagnostics engine. if (!DiagGenerationAsCompilation) sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); assert(!DiagConsumerFinished && "attempt to reuse finished consumer"); - ScanInstance.createDiagnostics(*FS, DiagConsumer, - /*ShouldOwnClient=*/false); + ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); if (!ScanInstance.hasDiagnostics()) return false; if (VerboseOS) @@ -596,13 +597,8 @@ class DependencyScanningAction { ScanInstance.getHeaderSearchOpts().ModulesIncludeVFSUsage = any(Service.getOptimizeArgs() & ScanningOptimizations::VFS); - // Support for virtual file system overlays. - FS = createVFSFromCompilerInvocation(ScanInstance.getInvocation(), - ScanInstance.getDiagnostics(), - std::move(FS)); - // Create a new FileManager to match the invocation's FileSystemOptions. - auto *FileMgr = ScanInstance.createFileManager(FS); + auto *FileMgr = ScanInstance.createFileManager(); // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 53339566e310e..6905c5581cedf 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -453,8 +453,7 @@ bool FrontendActionFactory::runInvocation( std::unique_ptr ScopedToolAction(create()); // Create the compiler's actual diagnostics engine. - Compiler.createDiagnostics(Files->getVirtualFileSystem(), DiagConsumer, - /*ShouldOwnClient=*/false); + Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); if (!Compiler.hasDiagnostics()) return false; diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp index 7f5df9259889b..5595c3612f517 100644 --- a/clang/tools/clang-import-test/clang-import-test.cpp +++ b/clang/tools/clang-import-test/clang-import-test.cpp @@ -207,8 +207,8 @@ std::unique_ptr BuildCompilerInstance() { auto Ins = std::make_unique(std::move(Inv)); - Ins->createDiagnostics(*llvm::vfs::getRealFileSystem(), DC.release(), - /*ShouldOwnClient=*/true); + Ins->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DC.get()); + Ins->createDiagnostics(DC.release(), /*ShouldOwnClient=*/true); TargetInfo *TI = TargetInfo::CreateTargetInfo( Ins->getDiagnostics(), Ins->getInvocation().getTargetOpts()); diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp index 6bc642f971a48..49d84069e86f4 100644 --- a/clang/tools/clang-installapi/ClangInstallAPI.cpp +++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp @@ -114,7 +114,7 @@ static bool run(ArrayRef Args, const char *ProgName) { // Set up compilation. std::unique_ptr CI(new CompilerInstance()); CI->setFileManager(FM.get()); - CI->createDiagnostics(FM->getVirtualFileSystem()); + CI->createDiagnostics(); if (!CI->hasDiagnostics()) return EXIT_FAILURE; diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index d5fc4db7a0e68..49bb7e5e63d19 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -275,8 +275,11 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { Clang->getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(Argv0, MainAddr); + /// Create the actual file system. + Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer); + // Create the actual diagnostics engine. - Clang->createDiagnostics(*llvm::vfs::getRealFileSystem()); + Clang->createDiagnostics(); if (!Clang->hasDiagnostics()) return 1; @@ -347,8 +350,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { // options are stored in the compiler invocation and we can recreate the VFS // from the compiler invocation. if (!Clang->hasFileManager()) - Clang->createFileManager(createVFSFromCompilerInvocation( - Clang->getInvocation(), Clang->getDiagnostics())); + Clang->createFileManager(); llvm::vfs::OnDiskOutputBackend Backend; if (std::optional profilerOutput = diff --git a/clang/unittests/AST/ExternalASTSourceTest.cpp b/clang/unittests/AST/ExternalASTSourceTest.cpp index 11715bb8ce7cd..98d708707bc99 100644 --- a/clang/unittests/AST/ExternalASTSourceTest.cpp +++ b/clang/unittests/AST/ExternalASTSourceTest.cpp @@ -57,7 +57,8 @@ bool testExternalASTSource(ExternalASTSource *Source, StringRef FileContents) { CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags); CompilerInstance Compiler(std::move(Invocation)); - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); TestFrontendAction Action(Source); return Compiler.ExecuteAction(Action); diff --git a/clang/unittests/CodeGen/TestCompiler.h b/clang/unittests/CodeGen/TestCompiler.h index a6fec7fb0945d..66e45dd259935 100644 --- a/clang/unittests/CodeGen/TestCompiler.h +++ b/clang/unittests/CodeGen/TestCompiler.h @@ -36,7 +36,8 @@ struct TestCompiler { clang::CodeGenOptions CGO = clang::CodeGenOptions()) { compiler.getLangOpts() = LO; compiler.getCodeGenOpts() = CGO; - compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + compiler.createDiagnostics(); std::string TrStr = llvm::Triple::normalize(llvm::sys::getProcessTriple()); llvm::Triple Tr(TrStr); diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index 670090a01b0d3..56a961370c0be 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -579,7 +579,8 @@ TEST(CompilerInvocation, SplitSwarfSingleCrash) { TEST(ToolChainTest, UEFICallingConventionTest) { clang::CompilerInstance compiler; - compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + compiler.createDiagnostics(); std::string TrStr = "x86_64-unknown-uefi"; llvm::Triple Tr(TrStr); diff --git a/clang/unittests/Frontend/CodeGenActionTest.cpp b/clang/unittests/Frontend/CodeGenActionTest.cpp index b2792c44ba5fe..182afdc7ea313 100644 --- a/clang/unittests/Frontend/CodeGenActionTest.cpp +++ b/clang/unittests/Frontend/CodeGenActionTest.cpp @@ -52,7 +52,8 @@ TEST(CodeGenTest, TestNullCodeGen) { Invocation->getFrontendOpts().ProgramAction = EmitLLVM; Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler(std::move(Invocation)); - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); EXPECT_TRUE(Compiler.hasDiagnostics()); std::unique_ptr Act(new NullCodeGenAction); @@ -69,7 +70,8 @@ TEST(CodeGenTest, CodeGenFromIRMemBuffer) { Invocation->getFrontendOpts().ProgramAction = frontend::EmitLLVMOnly; Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler(std::move(Invocation)); - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); EXPECT_TRUE(Compiler.hasDiagnostics()); EmitLLVMOnlyAction Action; diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index 459a3864887e1..47feb366af896 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -72,6 +72,7 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) { // in the CompilerInvocation (as we don't explicitly set our own). CompilerInstance Instance(std::move(CInvok)); Instance.setDiagnostics(Diags.get()); + Instance.createVirtualFileSystem(); Instance.createFileManager(); // Check if the virtual file exists which means that our VFS is used by the @@ -135,8 +136,9 @@ TEST(CompilerInstance, MultipleInputsCleansFileIDs) { ASSERT_TRUE(CInvok) << "could not create compiler invocation"; CompilerInstance Instance(std::move(CInvok)); + Instance.setVirtualFileSystem(VFS); Instance.setDiagnostics(Diags.get()); - Instance.createFileManager(VFS); + Instance.createFileManager(); // Run once for `a.cc` and then for `a.h`. This makes sure we get the same // file ID for `b.h` in the second run as `a.h` from first run. diff --git a/clang/unittests/Frontend/FrontendActionTest.cpp b/clang/unittests/Frontend/FrontendActionTest.cpp index 4e040783c923e..125940b44170c 100644 --- a/clang/unittests/Frontend/FrontendActionTest.cpp +++ b/clang/unittests/Frontend/FrontendActionTest.cpp @@ -91,7 +91,8 @@ TEST(ASTFrontendAction, Sanity) { invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler(std::move(invocation)); - compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + compiler.createDiagnostics(); TestASTFrontendAction test_action; ASSERT_TRUE(compiler.ExecuteAction(test_action)); @@ -110,7 +111,8 @@ TEST(ASTFrontendAction, IncrementalParsing) { invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler(std::move(invocation)); - compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + compiler.createDiagnostics(); TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true); ASSERT_TRUE(compiler.ExecuteAction(test_action)); @@ -136,7 +138,8 @@ TEST(ASTFrontendAction, LateTemplateIncrementalParsing) { invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance compiler(std::move(invocation)); - compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + compiler.createDiagnostics(); TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true, /*actOnEndOfTranslationUnit=*/true); @@ -181,7 +184,8 @@ TEST(PreprocessorFrontendAction, EndSourceFile) { Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler(std::move(Invocation)); - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); TestPPCallbacks *Callbacks = new TestPPCallbacks; TestPPCallbacksFrontendAction TestAction(Callbacks); @@ -242,8 +246,8 @@ TEST(ASTFrontendAction, ExternalSemaSource) { Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; CompilerInstance Compiler(std::move(Invocation)); auto *TDC = new TypoDiagnosticConsumer; - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem(), TDC, - /*ShouldOwnClient=*/true); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(TDC, /*ShouldOwnClient=*/true); Compiler.setExternalSemaSource(new TypoExternalSemaSource(Compiler)); SyntaxOnlyAction TestAction; @@ -274,7 +278,8 @@ TEST(GeneratePCHFrontendAction, CacheGeneratedPCH) { Invocation->getFrontendOpts().ProgramAction = frontend::GeneratePCH; Invocation->getTargetOpts().Triple = "x86_64-apple-darwin19.0.0"; CompilerInstance Compiler(std::move(Invocation)); - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); GeneratePCHAction TestAction; ASSERT_TRUE(Compiler.ExecuteAction(TestAction)); diff --git a/clang/unittests/Frontend/OutputStreamTest.cpp b/clang/unittests/Frontend/OutputStreamTest.cpp index dfb5a544cb88a..9e288f86351ca 100644 --- a/clang/unittests/Frontend/OutputStreamTest.cpp +++ b/clang/unittests/Frontend/OutputStreamTest.cpp @@ -38,7 +38,8 @@ TEST(FrontendOutputTests, TestOutputStream) { new raw_svector_ostream(IRBuffer)); Compiler.setOutputStream(std::move(IRStream)); - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem()); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); bool Success = ExecuteCompilerInvocation(&Compiler); EXPECT_TRUE(Success); @@ -62,8 +63,8 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamShared) { Compiler.setOutputStream(std::make_unique()); DiagnosticOptions DiagOpts; - Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem(), - new TextDiagnosticPrinter(llvm::nulls(), DiagOpts), + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(new TextDiagnosticPrinter(llvm::nulls(), DiagOpts), true); Compiler.setVerboseOutputStream(VerboseStream); @@ -92,8 +93,8 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamOwned) { Compiler.setOutputStream(std::make_unique()); DiagnosticOptions DiagOpts; + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); Compiler.createDiagnostics( - *llvm::vfs::getRealFileSystem(), new TextDiagnosticPrinter(llvm::nulls(), DiagOpts), true); Compiler.setVerboseOutputStream(std::move(VerboseStream)); diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp index 970eeef3c953e..fdef7849aa872 100644 --- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp +++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp @@ -91,10 +91,8 @@ export int aa = 43; Instance.getFrontendOpts().OutputFile = BMIPath; - if (auto VFSWithRemapping = createVFSFromCompilerInvocation( - Instance.getInvocation(), Instance.getDiagnostics(), CIOpts.VFS)) - CIOpts.VFS = VFSWithRemapping; - Instance.createFileManager(CIOpts.VFS); + Instance.createVirtualFileSystem(CIOpts.VFS); + Instance.createFileManager(); Instance.getHeaderSearchOpts().ValidateASTInputFilesContent = true; @@ -123,7 +121,8 @@ export int aa = 43; CompilerInstance Clang(std::move(Invocation)); Clang.setDiagnostics(Diags.get()); - FileManager *FM = Clang.createFileManager(CIOpts.VFS); + Clang.createVirtualFileSystem(CIOpts.VFS); + FileManager *FM = Clang.createFileManager(); Clang.createSourceManager(*FM); EXPECT_TRUE(Clang.createTarget()); diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp index de6e13a738cb8..dbf2076b40396 100644 --- a/clang/unittests/Serialization/ModuleCacheTest.cpp +++ b/clang/unittests/Serialization/ModuleCacheTest.cpp @@ -121,6 +121,7 @@ TEST_F(ModuleCacheTest, CachedModuleNewPath) { createInvocationAndEnableFree(Args, CIOpts); ASSERT_TRUE(Invocation); CompilerInstance Instance(std::move(Invocation)); + Instance.setVirtualFileSystem(CIOpts.VFS); Instance.setDiagnostics(Diags.get()); SyntaxOnlyAction Action; ASSERT_TRUE(Instance.ExecuteAction(Action)); @@ -145,6 +146,7 @@ TEST_F(ModuleCacheTest, CachedModuleNewPath) { CompilerInstance Instance2(std::move(Invocation2), Instance.getPCHContainerOperations(), &Instance.getModuleCache()); + Instance2.setVirtualFileSystem(CIOpts.VFS); Instance2.setDiagnostics(Diags.get()); SyntaxOnlyAction Action2; ASSERT_FALSE(Instance2.ExecuteAction(Action2)); @@ -171,6 +173,7 @@ TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) { createInvocationAndEnableFree(Args, CIOpts); ASSERT_TRUE(Invocation); CompilerInstance Instance(std::move(Invocation)); + Instance.setVirtualFileSystem(CIOpts.VFS); Instance.setDiagnostics(Diags.get()); SyntaxOnlyAction Action; ASSERT_TRUE(Instance.ExecuteAction(Action)); @@ -189,6 +192,7 @@ TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) { CompilerInstance Instance2(std::move(Invocation2), Instance.getPCHContainerOperations(), &Instance.getModuleCache()); + Instance2.setVirtualFileSystem(CIOpts.VFS); Instance2.setDiagnostics(Diags.get()); SyntaxOnlyAction Action2; ASSERT_FALSE(Instance2.ExecuteAction(Action2)); diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp index 05efeef990d43..f091e51e86c93 100644 --- a/clang/unittests/Serialization/NoCommentsTest.cpp +++ b/clang/unittests/Serialization/NoCommentsTest.cpp @@ -99,6 +99,7 @@ void foo() {} ASSERT_TRUE(Invocation); CompilerInstance Instance(std::move(Invocation)); + Instance.createVirtualFileSystem(CIOpts.VFS); Instance.setDiagnostics(Diags.get()); Instance.getFrontendOpts().OutputFile = CacheBMIPath; GenerateReducedModuleInterfaceAction Action; diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp index c43520f79b02c..9f7ec8182f748 100644 --- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp +++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp @@ -113,12 +113,8 @@ export using ::E; auto Clang = std::make_unique(std::move(Invocation)); Clang->setDiagnostics(Diags.get()); - - if (auto VFSWithRemapping = createVFSFromCompilerInvocation( - Clang->getInvocation(), Clang->getDiagnostics(), VFS)) - VFS = VFSWithRemapping; - - Clang->createFileManager(VFS); + Clang->createVirtualFileSystem(VFS); + Clang->createFileManager(); EXPECT_TRUE(Clang->createTarget()); Buffer.release(); diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp index 85d36b5d21423..d85743da31358 100644 --- a/clang/unittests/Support/TimeProfilerTest.cpp +++ b/clang/unittests/Support/TimeProfilerTest.cpp @@ -53,8 +53,6 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef File, FS->addFile(Header.getKey(), 0, MemoryBuffer::getMemBuffer(Header.getValue())); } - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), FS)); auto Invocation = std::make_shared(); std::vector Args = {Standard.data(), File.data()}; @@ -64,8 +62,9 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef File, CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags); CompilerInstance Compiler(std::move(Invocation)); - Compiler.createDiagnostics(Files->getVirtualFileSystem()); - Compiler.setFileManager(Files.get()); + Compiler.setVirtualFileSystem(std::move(FS)); + Compiler.createDiagnostics(); + Compiler.createFileManager(); class TestFrontendAction : public ASTFrontendAction { private: diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp index 256a276702c67..ec5e36e07272b 100644 --- a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp +++ b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp @@ -65,8 +65,7 @@ class TestDependencyScanningAction : public tooling::ToolAction { std::move(PCHContainerOps)); Compiler.setFileManager(FileMgr); - Compiler.createDiagnostics(FileMgr->getVirtualFileSystem(), DiagConsumer, - /*ShouldOwnClient=*/false); + Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); if (!Compiler.hasDiagnostics()) return false; diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index dbebbbd38093e..62d245734c288 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -2210,7 +2210,9 @@ class CommandObjectTargetModulesDumpClangPCMInfo : public CommandObjectParsed { const char *clang_args[] = {"clang", pcm_path}; clang::CompilerInstance compiler(clang::createInvocation(clang_args)); - compiler.createDiagnostics(*FileSystem::Instance().GetVirtualFileSystem()); + compiler.setVirtualFileSystem( + FileSystem::Instance().GetVirtualFileSystem()); + compiler.createDiagnostics(); // Pass empty deleter to not attempt to free memory that was allocated // outside of the current scope, possibly statically. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 8f88e4a2f1726..2bfd15630f60b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -801,14 +801,16 @@ ClangExpressionParser::ClangExpressionParser( m_compiler = std::make_unique(); // Make sure clang uses the same VFS as LLDB. - m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem()); + m_compiler->setVirtualFileSystem( + FileSystem::Instance().GetVirtualFileSystem()); + m_compiler->createFileManager(); // 2. Configure the compiler with a set of default options that are // appropriate for most situations. SetupTargetOpts(*m_compiler, *target_sp); // 3. Create and install the target on the compiler. - m_compiler->createDiagnostics(m_compiler->getVirtualFileSystem()); + m_compiler->createDiagnostics(); // Limit the number of error diagnostics we emit. // A value of 0 means no limit for both LLDB and Clang. m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit()); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index e314ffb1260dd..14f08d3039b81 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -745,7 +745,8 @@ ClangModulesDeclVendor::Create(Target &target) { auto instance = std::make_unique(invocation); // Make sure clang uses the same VFS as LLDB. - instance->createFileManager(FileSystem::Instance().GetVirtualFileSystem()); + instance->setVirtualFileSystem(FileSystem::Instance().GetVirtualFileSystem()); + instance->createFileManager(); instance->setDiagnostics(diagnostics_engine.get()); std::unique_ptr action(new clang::SyntaxOnlyAction); From 3f94fe080e0a0f711dfbbd793e8947d5c6a7d8e3 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 18 Sep 2025 11:14:37 -0700 Subject: [PATCH 12/41] Merge pull request #11450 from swiftlang/jan_svoboda/cas-fix-early-vfs [clang] Fix CAS initialization after upstream #158381 (cherry picked from commit 6d730024d6bc072ef25b5415036ec79f122bce13) --- clang/include/clang/Frontend/CompilerInstance.h | 2 +- clang/lib/Frontend/CompileJobCache.cpp | 2 +- clang/lib/Frontend/CompilerInstance.cpp | 10 +++++++--- clang/lib/Frontend/CompilerInvocation.cpp | 3 --- .../DependencyScanning/IncludeTreeActionController.cpp | 3 ++- clang/test/CAS/output-path-error.c | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 3fed94a024e53..3ad454005770b 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -1030,7 +1030,7 @@ class CompilerInstance : public ModuleLoader { std::pair, std::shared_ptr> - createCASDatabases(); + getOrCreateCASDatabases(); }; } // end namespace clang diff --git a/clang/lib/Frontend/CompileJobCache.cpp b/clang/lib/Frontend/CompileJobCache.cpp index 4d0355da01351..81597274ca5b8 100644 --- a/clang/lib/Frontend/CompileJobCache.cpp +++ b/clang/lib/Frontend/CompileJobCache.cpp @@ -296,7 +296,7 @@ std::optional CompileJobCache::initialize(CompilerInstance &Clang) { if (!CacheCompileJob) return std::nullopt; - std::tie(CAS, Cache) = Clang.createCASDatabases(); + std::tie(CAS, Cache) = Clang.getOrCreateCASDatabases(); if (!CAS || !Cache) return 1; // Exit with error! diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 75dfd40b09ee9..f9ebecde0d2a1 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -293,6 +293,10 @@ void CompilerInstance::createVirtualFileSystem( DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts, DC, /*ShouldOwnClient=*/false); + std::tie(CAS, ActionCache) = + getInvocation().getCASOpts().getOrCreateDatabases( + Diags, /*CreateEmptyCASOnFailure=*/false); + VFS = createVFSFromCompilerInvocation(getInvocation(), Diags, std::move(BaseFS), CAS); // FIXME: Should this go into createVFSFromCompilerInvocation? @@ -964,7 +968,7 @@ llvm::vfs::OutputBackend &CompilerInstance::getOrCreateOutputBackend() { std::pair, std::shared_ptr> -CompilerInstance::createCASDatabases() { +CompilerInstance::getOrCreateCASDatabases() { // Create a new CAS databases from the CompilerInvocation. Future calls to // createFileManager() will use the same CAS. std::tie(CAS, ActionCache) = @@ -976,13 +980,13 @@ CompilerInstance::createCASDatabases() { llvm::cas::ObjectStore &CompilerInstance::getOrCreateObjectStore() { if (!CAS) - createCASDatabases(); + getOrCreateCASDatabases(); return *CAS; } llvm::cas::ActionCache &CompilerInstance::getOrCreateActionCache() { if (!ActionCache) - createCASDatabases(); + getOrCreateCASDatabases(); return *ActionCache; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 95a7a46748722..2d1117e42c083 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1529,9 +1529,6 @@ createBaseFS(const FileSystemOptions &FSOpts, const FrontendOptions &FEOpts, const CASOptions &CASOpts, DiagnosticsEngine &Diags, IntrusiveRefCntPtr BaseFS, std::shared_ptr OverrideCAS) { - if (!OverrideCAS) - return BaseFS; - if (FSOpts.CASFileSystemRootID.empty() && FEOpts.CASIncludeTreeID.empty()) return BaseFS; diff --git a/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp b/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp index e27bd3e218017..c6900f9b84290 100644 --- a/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp +++ b/clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp @@ -282,10 +282,11 @@ void dependencies::addReversePrefixMappingFileSystem( llvm::PrefixMapper ReverseMapper; ReverseMapper.addInverseRange(PrefixMapper.getMappings()); ReverseMapper.sort(); - std::unique_ptr FS = + IntrusiveRefCntPtr FS = llvm::vfs::createPrefixMappingFileSystem( std::move(ReverseMapper), &ScanInstance.getVirtualFileSystem()); + ScanInstance.setVirtualFileSystem(FS); ScanInstance.getFileManager().setVirtualFileSystem(std::move(FS)); } diff --git a/clang/test/CAS/output-path-error.c b/clang/test/CAS/output-path-error.c index b217ba48402cf..a221f3bb29bf0 100644 --- a/clang/test/CAS/output-path-error.c +++ b/clang/test/CAS/output-path-error.c @@ -19,4 +19,4 @@ // RUN: cat %t/output.txt | FileCheck %s --check-prefix=ERROR // CACHE-MISS: remark: compile job cache miss -// ERROR: fatal error: CAS missing expected root-id +// ERROR: fatal error: CAS filesystem cannot be initialized from root-id 'llvmcas://{{.*}}': cannot get reference to root FS From f757fdd4b6951da9a8e11ac7795358e3f721fba2 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 18 Sep 2025 11:07:40 -0700 Subject: [PATCH 13/41] [clang] Pass VFS into `ASTUnit::LoadFromASTFile()` (#159166) This PR makes the `VFS` parameter to `ASTUnit::LoadFromASTFile()` required and explicit, rather than silently defaulting to the real file system. This makes it easy to correctly propagate the fully-configured VFS and load any input files like the rest of the compiler does. --- clang/include/clang/Frontend/ASTUnit.h | 7 +++---- clang/lib/CrossTU/CrossTranslationUnit.cpp | 4 ++-- clang/lib/Frontend/ASTMerge.cpp | 3 ++- clang/lib/Frontend/ASTUnit.cpp | 5 +++-- clang/lib/Frontend/FrontendAction.cpp | 9 +++++---- clang/tools/c-index-test/core_main.cpp | 7 ++++--- clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp | 4 ++-- clang/tools/libclang/CIndex.cpp | 7 ++++--- clang/unittests/Frontend/ASTUnitTest.cpp | 3 ++- 9 files changed, 27 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 1485192e8f1e3..b7ba65a8d85bc 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -706,16 +706,15 @@ class ASTUnit { /// \returns - The initialized ASTUnit or null if the AST failed to load. static std::unique_ptr LoadFromASTFile( StringRef Filename, const PCHContainerReader &PCHContainerRdr, - WhatToLoad ToLoad, std::shared_ptr DiagOpts, + WhatToLoad ToLoad, IntrusiveRefCntPtr VFS, + std::shared_ptr DiagOpts, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, const HeaderSearchOptions &HSOpts, const LangOptions *LangOpts = nullptr, bool OnlyLocalDecls = false, CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, bool AllowASTWithCompilerErrors = false, - bool UserFilesAreVolatile = false, - IntrusiveRefCntPtr VFS = - llvm::vfs::getRealFileSystem()); + bool UserFilesAreVolatile = false); private: /// Helper function for \c LoadFromCompilerInvocation() and diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index 2e8d56c0d206e..a3fe2f4325e9c 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -578,8 +578,8 @@ CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) { new DiagnosticsEngine(DiagID, *DiagOpts, DiagClient)); return ASTUnit::LoadFromASTFile( ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(), - ASTUnit::LoadEverything, DiagOpts, Diags, CI.getFileSystemOpts(), - CI.getHeaderSearchOpts()); + ASTUnit::LoadEverything, CI.getVirtualFileSystemPtr(), DiagOpts, Diags, + CI.getFileSystemOpts(), CI.getHeaderSearchOpts()); } /// Load the AST from a source-file, which is supposed to be located inside the diff --git a/clang/lib/Frontend/ASTMerge.cpp b/clang/lib/Frontend/ASTMerge.cpp index a4ce88351e28e..51925ec85e7b6 100644 --- a/clang/lib/Frontend/ASTMerge.cpp +++ b/clang/lib/Frontend/ASTMerge.cpp @@ -47,7 +47,8 @@ void ASTMergeAction::ExecuteAction() { /*ShouldOwnClient=*/true)); std::unique_ptr Unit = ASTUnit::LoadFromASTFile( ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, - nullptr, Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts()); + CI.getVirtualFileSystemPtr(), nullptr, Diags, CI.getFileSystemOpts(), + CI.getHeaderSearchOpts()); if (!Unit) continue; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index d756fd738b6a3..e4390b9f6f9d6 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -799,12 +799,13 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr Diags, std::unique_ptr ASTUnit::LoadFromASTFile( StringRef Filename, const PCHContainerReader &PCHContainerRdr, - WhatToLoad ToLoad, std::shared_ptr DiagOpts, + WhatToLoad ToLoad, IntrusiveRefCntPtr VFS, + std::shared_ptr DiagOpts, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, const HeaderSearchOptions &HSOpts, const LangOptions *LangOpts, bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors, - bool UserFilesAreVolatile, IntrusiveRefCntPtr VFS) { + bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(true)); // Recover resources if we crash before exiting this method. diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 3c7c9772d2fdd..e50f1be9ad8aa 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -904,7 +904,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, std::unique_ptr AST = ASTUnit::LoadFromASTFile( InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly, - nullptr, ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts()); + CI.getVirtualFileSystemPtr(), nullptr, ASTDiags, CI.getFileSystemOpts(), + CI.getHeaderSearchOpts()); if (!AST) return false; @@ -971,9 +972,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, StringRef InputFile = Input.getFile(); std::unique_ptr AST = ASTUnit::LoadFromASTFile( - InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, nullptr, - Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts(), - &CI.getLangOpts()); + InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, + CI.getVirtualFileSystemPtr(), nullptr, Diags, CI.getFileSystemOpts(), + CI.getHeaderSearchOpts(), &CI.getLangOpts()); if (!AST) return false; diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index 100e708feb721..c5dc54b98f3bd 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -369,12 +369,13 @@ static bool printSourceSymbolsFromModule(StringRef modulePath, HeaderSearchOptions HSOpts; + auto VFS = llvm::vfs::getRealFileSystem(); + auto DiagOpts = std::make_shared(); IntrusiveRefCntPtr Diags = - CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(), - *DiagOpts); + CompilerInstance::createDiagnostics(*VFS, *DiagOpts); std::unique_ptr AU = ASTUnit::LoadFromASTFile( - modulePath, *pchRdr, ASTUnit::LoadASTOnly, DiagOpts, Diags, + modulePath, *pchRdr, ASTUnit::LoadASTOnly, VFS, DiagOpts, Diags, FileSystemOpts, HSOpts, /*LangOpts=*/nullptr, /*OnlyLocalDecls=*/true, CaptureDiagsKind::None, /*AllowASTWithCompilerErrors=*/true, diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp index 0b621b849e92f..64cb012788548 100644 --- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp +++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp @@ -158,8 +158,8 @@ static bool HandleAST(StringRef AstPath) { std::unique_ptr Unit = ASTUnit::LoadFromASTFile( AstPath, CI->getPCHContainerOperations()->getRawReader(), - ASTUnit::LoadASTOnly, DiagOpts, DiagEngine, CI->getFileSystemOpts(), - CI->getHeaderSearchOpts()); + ASTUnit::LoadASTOnly, CI->getVirtualFileSystemPtr(), DiagOpts, DiagEngine, + CI->getFileSystemOpts(), CI->getHeaderSearchOpts()); if (!Unit) return false; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index a3d9340a2db73..ee87cd66b308b 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -4243,13 +4243,14 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx, FileSystemOptions FileSystemOpts; HeaderSearchOptions HSOpts; + auto VFS = llvm::vfs::getRealFileSystem(); + auto DiagOpts = std::make_shared(); IntrusiveRefCntPtr Diags = - CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(), - *DiagOpts); + CompilerInstance::createDiagnostics(*VFS, *DiagOpts); std::unique_ptr AU = ASTUnit::LoadFromASTFile( ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(), - ASTUnit::LoadEverything, DiagOpts, Diags, FileSystemOpts, HSOpts, + ASTUnit::LoadEverything, VFS, DiagOpts, Diags, FileSystemOpts, HSOpts, /*LangOpts=*/nullptr, CXXIdx->getOnlyLocalDecls(), CaptureDiagsKind::All, /*AllowASTWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/true); diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp index afa64b5e90a6d..268dab2b169a3 100644 --- a/clang/unittests/Frontend/ASTUnitTest.cpp +++ b/clang/unittests/Frontend/ASTUnitTest.cpp @@ -97,7 +97,8 @@ TEST_F(ASTUnitTest, SaveLoadPreservesLangOptionsInPrintingPolicy) { std::unique_ptr AU = ASTUnit::LoadFromASTFile( ASTFileName, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything, - DiagOpts, Diags, FileSystemOptions(), HSOpts); + llvm::vfs::getRealFileSystem(), DiagOpts, Diags, FileSystemOptions(), + HSOpts); if (!AU) FAIL() << "failed to load ASTUnit"; From 060686740156b26ac8080de54128a4a9c6a222c1 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 18 Sep 2025 14:53:40 -0700 Subject: [PATCH 14/41] [llvm][clang] Pass VFS to `llvm::cl` command line handling (#159174) This PR passes the VFS down to `llvm::cl` functions so that they don't assume the real file system. --- clang-tools-extra/clangd/tool/ClangdMain.cpp | 4 ++-- clang/lib/CodeGen/BackendUtil.cpp | 12 ++++++---- .../ExecuteCompilerInvocation.cpp | 4 +++- clang/tools/driver/cc1as_main.cpp | 5 +++- clang/tools/driver/driver.cpp | 21 +++++++++------- llvm/include/llvm/Support/CommandLine.h | 4 +++- llvm/lib/Support/CommandLine.cpp | 24 ++++++++++--------- llvm/tools/obj2yaml/obj2yaml.cpp | 2 +- llvm/tools/yaml2obj/yaml2obj.cpp | 2 +- llvm/unittests/Support/CommandLineTest.cpp | 12 +++++----- llvm/utils/FileCheck/FileCheck.cpp | 2 +- llvm/utils/split-file/split-file.cpp | 1 + 12 files changed, 54 insertions(+), 39 deletions(-) diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index f287439f10cab..3be88bd04b6d5 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -775,8 +775,8 @@ It should be used via an editor plugin rather than invoked directly. For more in clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. )"; llvm::cl::HideUnrelatedOptions(ClangdCategories); - llvm::cl::ParseCommandLineOptions(argc, argv, Overview, - /*Errs=*/nullptr, FlagsEnvVar); + llvm::cl::ParseCommandLineOptions(argc, argv, Overview, /*Errs=*/nullptr, + /*VFS=*/nullptr, FlagsEnvVar); if (Test) { if (!Sync.getNumOccurrences()) Sync = true; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 32afc66f4b742..96773d2685629 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -579,7 +579,8 @@ getInstrProfOptions(const CodeGenOptions &CodeGenOpts, return Options; } -static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) { +static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts, + vfs::FileSystem &VFS) { SmallVector BackendArgs; BackendArgs.push_back("clang"); // Fake program name. if (!CodeGenOpts.DebugPass.empty()) { @@ -599,8 +600,9 @@ static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) { // FIXME: The command line parser below is not thread-safe and shares a global // state, so this call might crash or overwrite the options of another Clang // instance in the same process. - llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, - BackendArgs.data()); + llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, BackendArgs.data(), + /*Overview=*/"", /*Errs=*/nullptr, + /*VFS=*/&VFS); } void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { @@ -1294,7 +1296,7 @@ void EmitAssemblyHelper::emitAssembly(BackendAction Action, std::unique_ptr OS, std::unique_ptr CasIDOS, BackendConsumer *BC) { - setCommandLineOpts(CodeGenOpts); + setCommandLineOpts(CodeGenOpts, CI.getVirtualFileSystem()); bool RequiresCodeGen = actionRequiresCodeGen(Action); CreateTargetMachine(RequiresCodeGen); @@ -1331,7 +1333,7 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); - setCommandLineOpts(CGOpts); + setCommandLineOpts(CGOpts, CI.getVirtualFileSystem()); // We can simply import the values mentioned in the combined index, since // we should only invoke this using the individual indexes written out diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 3a8f0d8dd8545..b17f5860a8682 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -260,7 +260,9 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str(); Args[NumArgs + 1] = nullptr; - llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); + llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"", + /*Errs=*/nullptr, + /*VFS=*/&Clang->getVirtualFileSystem()); } #if CLANG_ENABLE_STATIC_ANALYZER diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index 3b4a4b54392df..d2244e572d55e 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -685,6 +685,8 @@ int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, DiagOpts, DiagClient); + auto VFS = vfs::getRealFileSystem(); + // Set an error handler, so that any LLVM backend diagnostics go through our // error handler. ScopedFatalErrorHandler FatalErrorHandler @@ -723,7 +725,8 @@ int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Asm.LLVMArgs[i].c_str(); Args[NumArgs + 1] = nullptr; - llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); + llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"", + /*Errs=*/nullptr, /*VFS=*/VFS.get()); } // Execute the invocation, unless there were parsing errors. diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp index aca3577b410b0..987fec0bdfb29 100644 --- a/clang/tools/driver/driver.cpp +++ b/clang/tools/driver/driver.cpp @@ -217,7 +217,8 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, } static int ExecuteCC1Tool(SmallVectorImpl &ArgV, - const llvm::ToolContext &ToolContext) { + const llvm::ToolContext &ToolContext, + IntrusiveRefCntPtr VFS) { // If we call the cc1 tool from the clangDriver library (through // Driver::CC1Main), we need to clean up the options usage count. The options // are currently global, and they might have been used previously by the @@ -225,7 +226,8 @@ static int ExecuteCC1Tool(SmallVectorImpl &ArgV, llvm::cl::ResetAllOptionOccurrences(); llvm::BumpPtrAllocator A; - llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine); + llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine, + VFS.get()); if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) { llvm::errs() << toString(std::move(Err)) << '\n'; return 1; @@ -293,14 +295,16 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { bool ClangCLMode = IsClangCL(DriverMode); - if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, A)) { + auto VFS = llvm::vfs::getRealFileSystem(); + + if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, A, VFS.get())) { llvm::errs() << toString(std::move(Err)) << '\n'; return 1; } // Handle -cc1 integrated tools. if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1")) - return ExecuteCC1Tool(Args, ToolContext); + return ExecuteCC1Tool(Args, ToolContext, VFS); // Handle options that need handling before the real command line parsing in // Driver::BuildCompilation() @@ -382,7 +386,6 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { Diags.takeClient(), std::move(SerializedConsumer))); } - auto VFS = llvm::vfs::getRealFileSystem(); ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false); Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags, @@ -402,10 +405,10 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver)) return 1; - auto ExecuteCC1WithContext = - [&ToolContext](SmallVectorImpl &ArgV) { - return ExecuteCC1Tool(ArgV, ToolContext); - }; + auto ExecuteCC1WithContext = [&ToolContext, + &VFS](SmallVectorImpl &ArgV) { + return ExecuteCC1Tool(ArgV, ToolContext, VFS); + }; if (!UseNewCC1Process) { TheDriver.CC1Main = ExecuteCC1WithContext; // Ensure the CC1Command actually catches cc1 crashes diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index ca725b8ac8712..b81df756247c9 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -69,6 +69,7 @@ namespace cl { LLVM_ABI bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview = "", raw_ostream *Errs = nullptr, + vfs::FileSystem *VFS = nullptr, const char *EnvVar = nullptr, bool LongOptionsUseDoubleDash = false); @@ -2192,7 +2193,8 @@ class ExpansionContext { SmallVectorImpl &NewArgv); public: - LLVM_ABI ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T); + LLVM_ABI ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T, + vfs::FileSystem *FS = nullptr); ExpansionContext &setMarkEOLs(bool X) { MarkEOLs = X; diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 8491633df97e8..134df0df4cd99 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -188,6 +188,7 @@ class CommandLineParser { bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs = nullptr, + vfs::FileSystem *VFS = nullptr, bool LongOptionsUseDoubleDash = false); void forEachSubCommand(Option &Opt, function_ref Action) { @@ -1401,8 +1402,9 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, return true; } -ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T) - : Saver(A), Tokenizer(T), FS(vfs::getRealFileSystem().get()) {} +ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T, + vfs::FileSystem *FS) + : Saver(A), Tokenizer(T), FS(FS ? FS : vfs::getRealFileSystem().get()) {} bool ExpansionContext::findConfigFile(StringRef FileName, SmallVectorImpl &FilePath) { @@ -1461,7 +1463,7 @@ Error ExpansionContext::readConfigFile(StringRef CfgFile, static void initCommonOptions(); bool cl::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs, - const char *EnvVar, + vfs::FileSystem *VFS, const char *EnvVar, bool LongOptionsUseDoubleDash) { initCommonOptions(); SmallVector NewArgv; @@ -1482,8 +1484,8 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv, int NewArgc = static_cast(NewArgv.size()); // Parse all options. - return GlobalParser->ParseCommandLineOptions(NewArgc, &NewArgv[0], Overview, - Errs, LongOptionsUseDoubleDash); + return GlobalParser->ParseCommandLineOptions( + NewArgc, &NewArgv[0], Overview, Errs, VFS, LongOptionsUseDoubleDash); } /// Reset all options at least once, so that we can parse different options. @@ -1503,17 +1505,17 @@ void CommandLineParser::ResetAllOptionOccurrences() { } } -bool CommandLineParser::ParseCommandLineOptions(int argc, - const char *const *argv, - StringRef Overview, - raw_ostream *Errs, - bool LongOptionsUseDoubleDash) { +bool CommandLineParser::ParseCommandLineOptions( + int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs, + vfs::FileSystem *VFS, bool LongOptionsUseDoubleDash) { assert(hasOptions() && "No options specified!"); ProgramOverview = Overview; bool IgnoreErrors = Errs; if (!Errs) Errs = &errs(); + if (!VFS) + VFS = vfs::getRealFileSystem().get(); bool ErrorParsing = false; // Expand response files. @@ -1524,7 +1526,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, #else auto Tokenize = cl::TokenizeGNUCommandLine; #endif - ExpansionContext ECtx(A, Tokenize); + ExpansionContext ECtx(A, Tokenize, VFS); if (Error Err = ECtx.expandResponseFiles(newArgv)) { *Errs << toString(std::move(Err)) << '\n'; return false; diff --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp index 63c8cc55ee2d4..94c38d1032c22 100644 --- a/llvm/tools/obj2yaml/obj2yaml.cpp +++ b/llvm/tools/obj2yaml/obj2yaml.cpp @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) { cl::HideUnrelatedOptions(Cat); cl::ParseCommandLineOptions( argc, argv, "Dump a YAML description from an object file", nullptr, - nullptr, /*LongOptionsUseDoubleDash=*/true); + nullptr, nullptr, /*LongOptionsUseDoubleDash=*/true); std::error_code EC; std::unique_ptr Out( diff --git a/llvm/tools/yaml2obj/yaml2obj.cpp b/llvm/tools/yaml2obj/yaml2obj.cpp index dcd6dfcd3de2a..662648b599954 100644 --- a/llvm/tools/yaml2obj/yaml2obj.cpp +++ b/llvm/tools/yaml2obj/yaml2obj.cpp @@ -115,7 +115,7 @@ int main(int argc, char **argv) { cl::HideUnrelatedOptions(Cat); cl::ParseCommandLineOptions( argc, argv, "Create an object file from a YAML description", nullptr, - nullptr, /*LongOptionsUseDoubleDash=*/true); + nullptr, nullptr, /*LongOptionsUseDoubleDash=*/true); constexpr StringRef ProgName = "yaml2obj"; auto ErrHandler = [&](const Twine &Msg) { diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 3df4107ebf439..15d47a7642980 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -1901,20 +1901,20 @@ TEST(CommandLineTest, LongOptions) { // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and // `val1` is unexpected. - EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), - &OS, nullptr, true)); + EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), &OS, nullptr, + nullptr, true)); EXPECT_FALSE(Errs.empty()); Errs.clear(); cl::ResetAllOptionOccurrences(); // Works because `-a` is treated differently than `--ab`. - EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), - &OS, nullptr, true)); + EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), &OS, nullptr, + nullptr, true)); EXPECT_TRUE(Errs.empty()); Errs.clear(); cl::ResetAllOptionOccurrences(); // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option. - EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), - &OS, nullptr, true)); + EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), &OS, nullptr, + nullptr, true)); EXPECT_TRUE(OptA); EXPECT_TRUE(OptBLong); EXPECT_STREQ("val1", OptAB.c_str()); diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp index 9cf3a3164dfec..185b6b30994fc 100644 --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -735,7 +735,7 @@ int main(int argc, char **argv) { InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr, - "FILECHECK_OPTS"); + /*VFS*/ nullptr, "FILECHECK_OPTS"); // Select -dump-input* values. The -help documentation specifies the default // value and which value to choose if an option is specified multiple times. diff --git a/llvm/utils/split-file/split-file.cpp b/llvm/utils/split-file/split-file.cpp index 672877adaba31..c7e9ff4b2b682 100644 --- a/llvm/utils/split-file/split-file.cpp +++ b/llvm/utils/split-file/split-file.cpp @@ -148,6 +148,7 @@ int main(int argc, const char **argv) { "Split input into multiple parts separated by regex '^(.|//)--- ' and " "extract the part specified by '^(.|//)--- '\n", nullptr, + /*VFS=*/nullptr, /*EnvVar=*/nullptr, /*LongOptionsUseDoubleDash=*/true); From bf1dce3141014a2f3b58da10814a9c200a2939e1 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 19 Sep 2025 13:01:02 -0700 Subject: [PATCH 15/41] [clang][analyzer] Load config through the proper VFS (#159164) This PR ensures that the Clang static analyzer loads the config file through the properly-configured VFS rather than through the bare real file system. This enables correctly going through VFS overlays, unifying the behavior with the rest of the compiler. --- clang/lib/StaticAnalyzer/Checkers/Yaml.h | 8 ++++++-- .../Inputs/taint-generic-config-vfs.json | 17 +++++++++++++++++ clang/test/Analysis/taint-generic.c | 6 +++++- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 clang/test/Analysis/Inputs/taint-generic-config-vfs.json diff --git a/clang/lib/StaticAnalyzer/Checkers/Yaml.h b/clang/lib/StaticAnalyzer/Checkers/Yaml.h index b2d17420686ee..ec521cbfcdc8e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Yaml.h +++ b/clang/lib/StaticAnalyzer/Checkers/Yaml.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKER_YAML_H #define LLVM_CLANG_LIB_STATICANALYZER_CHECKER_YAML_H +#include "clang/Basic/SourceManager.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLTraits.h" @@ -31,9 +32,12 @@ std::optional getConfiguration(CheckerManager &Mgr, Checker *Chk, if (ConfigFile.trim().empty()) return std::nullopt; - llvm::vfs::FileSystem *FS = llvm::vfs::getRealFileSystem().get(); + auto &VFS = Mgr.getASTContext() + .getSourceManager() + .getFileManager() + .getVirtualFileSystem(); llvm::ErrorOr> Buffer = - FS->getBufferForFile(ConfigFile.str()); + VFS.getBufferForFile(ConfigFile.str()); if (Buffer.getError()) { Mgr.reportInvalidCheckerOptionValue(Chk, Option, diff --git a/clang/test/Analysis/Inputs/taint-generic-config-vfs.json b/clang/test/Analysis/Inputs/taint-generic-config-vfs.json new file mode 100644 index 0000000000000..74f3cd99a9707 --- /dev/null +++ b/clang/test/Analysis/Inputs/taint-generic-config-vfs.json @@ -0,0 +1,17 @@ +{ + 'version': 0, + 'use-external-names': true, + 'roots': [ + { + 'name': 'DIR', + 'type': 'directory', + 'contents': [ + { + 'name': 'taint-generic-config-virtual.yaml', + 'type': 'file', + 'external-contents': 'DIR/taint-generic-config.yaml' + } + ] + } + ] +} diff --git a/clang/test/Analysis/taint-generic.c b/clang/test/Analysis/taint-generic.c index 9d6d2942df4a9..6017483f06b6d 100644 --- a/clang/test/Analysis/taint-generic.c +++ b/clang/test/Analysis/taint-generic.c @@ -1,3 +1,6 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: sed -e "s|DIR|%/S/Inputs|g" %S/Inputs/taint-generic-config-vfs.json > %t/taint-generic-config-vfs.json + // RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ // RUN: -Wno-incompatible-library-redeclaration -verify %s \ // RUN: -analyzer-checker=optin.taint.GenericTaint \ @@ -6,7 +9,8 @@ // RUN: -analyzer-checker=security.ArrayBound \ // RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -analyzer-config \ -// RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml +// RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-virtual.yaml \ +// RUN: -ivfsoverlay %t/taint-generic-config-vfs.json // RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ // RUN: -Wno-incompatible-library-redeclaration -verify %s \ From 54543048c5e3bb7acbdb50dd94e5a15fffa9fcd2 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 22 Sep 2025 10:06:52 -0700 Subject: [PATCH 16/41] [clang] Load `-fms-secure-hotpatch-functions-file=` through the VFS (#160146) This PR uses the correctly-configured VFS to load the file specified via `-fms-secure-hotpatch-functions-file=`, matching other input files of the compiler. --- clang/lib/CodeGen/CodeGenModule.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 276752150fea1..54a4fdfd11456 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -531,8 +531,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, if (!CGO.MSSecureHotPatchFunctionsFile.empty() || !CGO.MSSecureHotPatchFunctionsList.empty()) { if (!CGO.MSSecureHotPatchFunctionsFile.empty()) { - auto BufOrErr = - llvm::MemoryBuffer::getFile(CGO.MSSecureHotPatchFunctionsFile); + auto BufOrErr = FS->getBufferForFile(CGO.MSSecureHotPatchFunctionsFile); if (BufOrErr) { const llvm::MemoryBuffer &FileBuffer = **BufOrErr; for (llvm::line_iterator I(FileBuffer.getMemBufferRef(), true), E; From 5650352481d9665b73c01be48377d72a92bc35cc Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 25 Sep 2025 10:15:47 -0700 Subject: [PATCH 17/41] [llvm] Add `vfs::FileSystem` to `PassBuilder` (#160188) Some LLVM passes need access to the filesystem to read configuration files and similar. In some places, this is achieved by grabbing the VFS from `PGOOptions`, but some passes don't have access to these and resort to just calling `vfs::getRealFileSystem()`. This PR allows setting the VFS directly on `PassBuilder` that's able to pass it down to all passes that need it. --- clang/lib/CodeGen/BackendUtil.cpp | 33 +++++++------- flang/lib/Frontend/FrontendActions.cpp | 6 +-- llvm/include/llvm/Passes/PassBuilder.h | 19 ++++---- llvm/include/llvm/Support/PGOOptions.h | 11 +---- .../Instrumentation/DataFlowSanitizer.h | 7 ++- llvm/lib/LTO/LTOBackend.cpp | 17 ++++---- llvm/lib/Passes/PassBuilder.cpp | 5 ++- llvm/lib/Passes/PassBuilderPipelines.cpp | 43 ++++++++----------- llvm/lib/Support/PGOOptions.cpp | 9 +--- llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp | 2 + .../Instrumentation/DataFlowSanitizer.cpp | 12 +++--- llvm/tools/opt/NewPMDriver.cpp | 14 +++--- 12 files changed, 80 insertions(+), 98 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 96773d2685629..908b67f4b2f65 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -803,7 +803,8 @@ static void addSanitizers(const Triple &TargetTriple, HWASanPass(SanitizerKind::KernelHWAddress, true); if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) { - MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles)); + MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles, + PB.getVirtualFileSystemPtr())); } }; if (ClSanitizeOnOptimizerEarlyEP) { @@ -855,9 +856,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (CodeGenOpts.hasProfileIRInstr()) // -fprofile-generate. PGOOpt = PGOOptions(getProfileGenName(CodeGenOpts), "", "", - CodeGenOpts.MemoryProfileUsePath, nullptr, - PGOOptions::IRInstr, PGOOptions::NoCSAction, - ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, + CodeGenOpts.MemoryProfileUsePath, PGOOptions::IRInstr, + PGOOptions::NoCSAction, ClPGOColdFuncAttr, + CodeGenOpts.DebugInfoForProfiling, /*PseudoProbeForProfiling=*/false, CodeGenOpts.AtomicProfileUpdate); else if (CodeGenOpts.hasProfileIRUse()) { @@ -866,32 +867,30 @@ void EmitAssemblyHelper::RunOptimizationPipeline( : PGOOptions::NoCSAction; PGOOpt = PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "", CodeGenOpts.ProfileRemappingFile, - CodeGenOpts.MemoryProfileUsePath, VFS, - PGOOptions::IRUse, CSAction, ClPGOColdFuncAttr, + CodeGenOpts.MemoryProfileUsePath, PGOOptions::IRUse, + CSAction, ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling); } else if (!CodeGenOpts.SampleProfileFile.empty()) // -fprofile-sample-use PGOOpt = PGOOptions( CodeGenOpts.SampleProfileFile, "", CodeGenOpts.ProfileRemappingFile, - CodeGenOpts.MemoryProfileUsePath, VFS, PGOOptions::SampleUse, + CodeGenOpts.MemoryProfileUsePath, PGOOptions::SampleUse, PGOOptions::NoCSAction, ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, CodeGenOpts.PseudoProbeForProfiling); else if (!CodeGenOpts.MemoryProfileUsePath.empty()) // -fmemory-profile-use (without any of the above options) - PGOOpt = PGOOptions("", "", "", CodeGenOpts.MemoryProfileUsePath, VFS, + PGOOpt = PGOOptions("", "", "", CodeGenOpts.MemoryProfileUsePath, PGOOptions::NoAction, PGOOptions::NoCSAction, ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling); else if (CodeGenOpts.PseudoProbeForProfiling) // -fpseudo-probe-for-profiling - PGOOpt = - PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr, - PGOOptions::NoAction, PGOOptions::NoCSAction, - ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, true); + PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", PGOOptions::NoAction, + PGOOptions::NoCSAction, ClPGOColdFuncAttr, + CodeGenOpts.DebugInfoForProfiling, true); else if (CodeGenOpts.DebugInfoForProfiling) // -fdebug-info-for-profiling - PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr, - PGOOptions::NoAction, PGOOptions::NoCSAction, - ClPGOColdFuncAttr, true); + PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", PGOOptions::NoAction, + PGOOptions::NoCSAction, ClPGOColdFuncAttr, true); // Check to see if we want to generate a CS profile. if (CodeGenOpts.hasProfileCSIRInstr()) { @@ -907,7 +906,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline( PGOOpt->CSAction = PGOOptions::CSIRInstr; } else PGOOpt = PGOOptions("", getProfileGenName(CodeGenOpts), "", - /*MemoryProfile=*/"", nullptr, PGOOptions::NoAction, + /*MemoryProfile=*/"", PGOOptions::NoAction, PGOOptions::CSIRInstr, ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling); } @@ -943,7 +942,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline( (CodeGenOpts.DebugPassManager || DebugPassStructure), CodeGenOpts.VerifyEach, PrintPassOpts); SI.registerCallbacks(PIC, &MAM); - PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC); + PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC, CI.getVirtualFileSystemPtr()); // Handle the assignment tracking feature options. switch (CodeGenOpts.getAssignmentTrackingMode()) { diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index b5f4f9421f633..692fbb1aea147 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -926,20 +926,18 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) { pgoOpt = llvm::PGOOptions(opts.InstrProfileOutput.empty() ? llvm::driver::getDefaultProfileGenName() : opts.InstrProfileOutput, - "", "", opts.MemoryProfileUsePath, nullptr, + "", "", opts.MemoryProfileUsePath, llvm::PGOOptions::IRInstr, llvm::PGOOptions::NoCSAction, llvm::PGOOptions::ColdFuncOpt::Default, false, /*PseudoProbeForProfiling=*/false, false); } else if (opts.hasProfileIRUse()) { - llvm::IntrusiveRefCntPtr VFS = - llvm::vfs::getRealFileSystem(); // -fprofile-use. auto CSAction = opts.hasProfileCSIRUse() ? llvm::PGOOptions::CSIRUse : llvm::PGOOptions::NoCSAction; pgoOpt = llvm::PGOOptions( opts.ProfileInstrumentUsePath, "", opts.ProfileRemappingFile, - opts.MemoryProfileUsePath, VFS, llvm::PGOOptions::IRUse, CSAction, + opts.MemoryProfileUsePath, llvm::PGOOptions::IRUse, CSAction, llvm::PGOOptions::ColdFuncOpt::Default, false); } diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h index e60a04067d102..1567307ed14bd 100644 --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -36,10 +36,6 @@ class StringRef; class AAManager; class TargetMachine; class ModuleSummaryIndex; -template class IntrusiveRefCntPtr; -namespace vfs { -class FileSystem; -} // namespace vfs /// Tunable parameters for passes in the default pipelines. class PipelineTuningOptions { @@ -113,6 +109,7 @@ class PassBuilder { PipelineTuningOptions PTO; std::optional PGOOpt; PassInstrumentationCallbacks *PIC; + IntrusiveRefCntPtr FS; public: /// A struct to capture parsed pass pipeline names. @@ -132,7 +129,8 @@ class PassBuilder { TargetMachine *TM = nullptr, PipelineTuningOptions PTO = PipelineTuningOptions(), std::optional PGOOpt = std::nullopt, - PassInstrumentationCallbacks *PIC = nullptr); + PassInstrumentationCallbacks *PIC = nullptr, + IntrusiveRefCntPtr FS = vfs::getRealFileSystem()); /// Cross register the analysis managers through their proxies. /// @@ -634,8 +632,7 @@ class PassBuilder { bool RunProfileGen, bool IsCS, bool AtomicCounterUpdate, std::string ProfileFile, - std::string ProfileRemappingFile, - IntrusiveRefCntPtr FS); + std::string ProfileRemappingFile); /// Returns PIC. External libraries can use this to register pass /// instrumentation callbacks. @@ -643,6 +640,11 @@ class PassBuilder { return PIC; } + /// Returns the virtual file system. + IntrusiveRefCntPtr getVirtualFileSystemPtr() const { + return FS; + } + // Invoke the callbacks registered for the various extension points. // Custom pipelines should use these to invoke the callbacks registered // by TargetMachines and other clients. @@ -774,8 +776,7 @@ class PassBuilder { void addPGOInstrPasses(ModulePassManager &MPM, OptimizationLevel Level, bool RunProfileGen, bool IsCS, bool AtomicCounterUpdate, std::string ProfileFile, - std::string ProfileRemappingFile, - IntrusiveRefCntPtr FS); + std::string ProfileRemappingFile); void addPostPGOLoopRotation(ModulePassManager &MPM, OptimizationLevel Level); bool isInstrumentedPGOUse() const; diff --git a/llvm/include/llvm/Support/PGOOptions.h b/llvm/include/llvm/Support/PGOOptions.h index 6527a18258bf8..fb1dc0cf4aa0a 100644 --- a/llvm/include/llvm/Support/PGOOptions.h +++ b/llvm/include/llvm/Support/PGOOptions.h @@ -14,16 +14,10 @@ #ifndef LLVM_SUPPORT_PGOOPTIONS_H #define LLVM_SUPPORT_PGOOPTIONS_H -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" namespace llvm { - -namespace vfs { -class FileSystem; -} // namespace vfs - /// A struct capturing PGO tunables. struct PGOOptions { enum PGOAction { NoAction, IRInstr, IRUse, SampleUse }; @@ -31,9 +25,7 @@ struct PGOOptions { enum class ColdFuncOpt { Default, OptSize, MinSize, OptNone }; LLVM_ABI PGOOptions(std::string ProfileFile, std::string CSProfileGenFile, std::string ProfileRemappingFile, - std::string MemoryProfile, - IntrusiveRefCntPtr FS, - PGOAction Action = NoAction, + std::string MemoryProfile, PGOAction Action = NoAction, CSPGOAction CSAction = NoCSAction, ColdFuncOpt ColdType = ColdFuncOpt::Default, bool DebugInfoForProfiling = false, @@ -53,7 +45,6 @@ struct PGOOptions { bool DebugInfoForProfiling; bool PseudoProbeForProfiling; bool AtomicCounterUpdate; - IntrusiveRefCntPtr FS; }; } // namespace llvm diff --git a/llvm/include/llvm/Transforms/Instrumentation/DataFlowSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/DataFlowSanitizer.h index af3662e4a6565..9c9d6afe1872f 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/DataFlowSanitizer.h +++ b/llvm/include/llvm/Transforms/Instrumentation/DataFlowSanitizer.h @@ -10,6 +10,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include @@ -19,11 +20,13 @@ class Module; class DataFlowSanitizerPass : public PassInfoMixin { private: std::vector ABIListFiles; + IntrusiveRefCntPtr FS; public: DataFlowSanitizerPass( - const std::vector &ABIListFiles = std::vector()) - : ABIListFiles(ABIListFiles) {} + const std::vector &ABIListFiles = std::vector(), + IntrusiveRefCntPtr FS = vfs::getRealFileSystem()) + : ABIListFiles(ABIListFiles), FS(std::move(FS)) {} LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); static bool isRequired() { return true; } }; diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 5e8cd12fe040b..783514eae9011 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -240,27 +240,26 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, unsigned OptLevel, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary) { - auto FS = vfs::getRealFileSystem(); std::optional PGOOpt; if (!Conf.SampleProfile.empty()) PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping, - /*MemoryProfile=*/"", FS, PGOOptions::SampleUse, + /*MemoryProfile=*/"", PGOOptions::SampleUse, PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default, true); else if (Conf.RunCSIRInstr) { PGOOpt = PGOOptions("", Conf.CSIRProfile, Conf.ProfileRemapping, - /*MemoryProfile=*/"", FS, PGOOptions::IRUse, + /*MemoryProfile=*/"", PGOOptions::IRUse, PGOOptions::CSIRInstr, PGOOptions::ColdFuncOpt::Default, Conf.AddFSDiscriminator); } else if (!Conf.CSIRProfile.empty()) { - PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping, - /*MemoryProfile=*/"", FS, PGOOptions::IRUse, - PGOOptions::CSIRUse, PGOOptions::ColdFuncOpt::Default, - Conf.AddFSDiscriminator); + PGOOpt = + PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping, + /*MemoryProfile=*/"", PGOOptions::IRUse, PGOOptions::CSIRUse, + PGOOptions::ColdFuncOpt::Default, Conf.AddFSDiscriminator); NoPGOWarnMismatch = !Conf.PGOWarnMismatch; } else if (Conf.AddFSDiscriminator) { - PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr, - PGOOptions::NoAction, PGOOptions::NoCSAction, + PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", PGOOptions::NoAction, + PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default, true); } TM->setPGOOption(PGOOpt); diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 8968ffa3a5c4b..b3f884481c643 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -479,8 +479,9 @@ class RequireAllMachineFunctionPropertiesPass PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO, std::optional PGOOpt, - PassInstrumentationCallbacks *PIC) - : TM(TM), PTO(PTO), PGOOpt(PGOOpt), PIC(PIC) { + PassInstrumentationCallbacks *PIC, + IntrusiveRefCntPtr FS) + : TM(TM), PTO(PTO), PGOOpt(PGOOpt), PIC(PIC), FS(std::move(FS)) { if (TM) TM->registerPassBuilderCallbacks(*this); if (PIC) { diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 27718be09a0f0..6e9c20fa7db2c 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -856,8 +856,7 @@ void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM, OptimizationLevel Level, bool RunProfileGen, bool IsCS, bool AtomicCounterUpdate, std::string ProfileFile, - std::string ProfileRemappingFile, - IntrusiveRefCntPtr FS) { + std::string ProfileRemappingFile) { assert(Level != OptimizationLevel::O0 && "Not expecting O0 here!"); if (!RunProfileGen) { @@ -892,10 +891,11 @@ void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM, MPM.addPass(InstrProfilingLoweringPass(Options, IsCS)); } -void PassBuilder::addPGOInstrPassesForO0( - ModulePassManager &MPM, bool RunProfileGen, bool IsCS, - bool AtomicCounterUpdate, std::string ProfileFile, - std::string ProfileRemappingFile, IntrusiveRefCntPtr FS) { +void PassBuilder::addPGOInstrPassesForO0(ModulePassManager &MPM, + bool RunProfileGen, bool IsCS, + bool AtomicCounterUpdate, + std::string ProfileFile, + std::string ProfileRemappingFile) { if (!RunProfileGen) { assert(!ProfileFile.empty() && "Profile use expecting a profile file!"); MPM.addPass( @@ -1141,8 +1141,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level, if (LoadSampleProfile) { // Annotate sample profile right after early FPM to ensure freshness of // the debug info. - MPM.addPass(SampleProfileLoaderPass(PGOOpt->ProfileFile, - PGOOpt->ProfileRemappingFile, Phase)); + MPM.addPass(SampleProfileLoaderPass( + PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile, Phase, FS)); // Cache ProfileSummaryAnalysis once to avoid the potential need to insert // RequireAnalysisPass for PSI before subsequent non-module passes. MPM.addPass(RequireAnalysisPass()); @@ -1238,8 +1238,7 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level, addPGOInstrPasses(MPM, Level, /*RunProfileGen=*/IsPGOInstrGen, /*IsCS=*/false, PGOOpt->AtomicCounterUpdate, - PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile, - PGOOpt->FS); + PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile); } else if (IsCtxProfGen || IsCtxProfUse) { MPM.addPass(PGOInstrumentationGen(PGOInstrumentationType::CTXPROF)); // In pre-link, we just want the instrumented IR. We use the contextual @@ -1262,10 +1261,10 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level, addPostPGOLoopRotation(MPM, Level); MPM.addPass(PGOCtxProfLoweringPass()); } else if (IsColdFuncOnlyInstrGen) { - addPGOInstrPasses( - MPM, Level, /* RunProfileGen */ true, /* IsCS */ false, - /* AtomicCounterUpdate */ false, InstrumentColdFuncOnlyPath, - /* ProfileRemappingFile */ "", IntrusiveRefCntPtr()); + addPGOInstrPasses(MPM, Level, /* RunProfileGen */ true, /* IsCS */ false, + /* AtomicCounterUpdate */ false, + InstrumentColdFuncOnlyPath, + /* ProfileRemappingFile */ ""); } if (IsPGOInstrGen || IsPGOInstrUse || IsCtxProfGen) @@ -1276,7 +1275,7 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level, EnableSampledInstr)); if (IsMemprofUse) - MPM.addPass(MemProfUsePass(PGOOpt->MemoryProfile, PGOOpt->FS)); + MPM.addPass(MemProfUsePass(PGOOpt->MemoryProfile, FS)); if (PGOOpt && (PGOOpt->Action == PGOOptions::IRUse || PGOOpt->Action == PGOOptions::SampleUse)) @@ -1485,13 +1484,11 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, if (PGOOpt->CSAction == PGOOptions::CSIRInstr) addPGOInstrPasses(MPM, Level, /*RunProfileGen=*/true, /*IsCS=*/true, PGOOpt->AtomicCounterUpdate, - PGOOpt->CSProfileGenFile, PGOOpt->ProfileRemappingFile, - PGOOpt->FS); + PGOOpt->CSProfileGenFile, PGOOpt->ProfileRemappingFile); else if (PGOOpt->CSAction == PGOOptions::CSIRUse) addPGOInstrPasses(MPM, Level, /*RunProfileGen=*/false, /*IsCS=*/true, PGOOpt->AtomicCounterUpdate, - PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile, - PGOOpt->FS); + PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile); } // Re-compute GlobalsAA here prior to function passes. This is particularly @@ -2091,13 +2088,11 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level, if (PGOOpt->CSAction == PGOOptions::CSIRInstr) addPGOInstrPasses(MPM, Level, /*RunProfileGen=*/true, /*IsCS=*/true, PGOOpt->AtomicCounterUpdate, - PGOOpt->CSProfileGenFile, PGOOpt->ProfileRemappingFile, - PGOOpt->FS); + PGOOpt->CSProfileGenFile, PGOOpt->ProfileRemappingFile); else if (PGOOpt->CSAction == PGOOptions::CSIRUse) addPGOInstrPasses(MPM, Level, /*RunProfileGen=*/false, /*IsCS=*/true, PGOOpt->AtomicCounterUpdate, - PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile, - PGOOpt->FS); + PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile); } // Break up allocas @@ -2259,7 +2254,7 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level, MPM, /*RunProfileGen=*/(PGOOpt->Action == PGOOptions::IRInstr), /*IsCS=*/false, PGOOpt->AtomicCounterUpdate, PGOOpt->ProfileFile, - PGOOpt->ProfileRemappingFile, PGOOpt->FS); + PGOOpt->ProfileRemappingFile); // Instrument function entry and exit before all inlining. MPM.addPass(createModuleToFunctionPassAdaptor( diff --git a/llvm/lib/Support/PGOOptions.cpp b/llvm/lib/Support/PGOOptions.cpp index 5981dff9e0946..ecfb0ca33f16c 100644 --- a/llvm/lib/Support/PGOOptions.cpp +++ b/llvm/lib/Support/PGOOptions.cpp @@ -13,8 +13,7 @@ using namespace llvm; PGOOptions::PGOOptions(std::string ProfileFile, std::string CSProfileGenFile, std::string ProfileRemappingFile, - std::string MemoryProfile, - IntrusiveRefCntPtr FS, PGOAction Action, + std::string MemoryProfile, PGOAction Action, CSPGOAction CSAction, ColdFuncOpt ColdType, bool DebugInfoForProfiling, bool PseudoProbeForProfiling, bool AtomicCounterUpdate) @@ -24,7 +23,7 @@ PGOOptions::PGOOptions(std::string ProfileFile, std::string CSProfileGenFile, DebugInfoForProfiling(DebugInfoForProfiling || (Action == SampleUse && !PseudoProbeForProfiling)), PseudoProbeForProfiling(PseudoProbeForProfiling), - AtomicCounterUpdate(AtomicCounterUpdate), FS(std::move(FS)) { + AtomicCounterUpdate(AtomicCounterUpdate) { // Note, we do allow ProfileFile.empty() for Action=IRUse LTO can // callback with IRUse action without ProfileFile. @@ -47,10 +46,6 @@ PGOOptions::PGOOptions(std::string ProfileFile, std::string CSProfileGenFile, assert(this->Action != NoAction || this->CSAction != NoCSAction || !this->MemoryProfile.empty() || this->DebugInfoForProfiling || this->PseudoProbeForProfiling); - - // If we need to use the profile, the VFS cannot be nullptr. - assert(this->FS || !(this->Action == IRUse || this->CSAction == CSIRUse || - !this->MemoryProfile.empty())); } PGOOptions::PGOOptions(const PGOOptions &) = default; diff --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp index 52302241fe365..9f34375c9feaf 100644 --- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -27,6 +27,8 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/Debug.h" +#include + using namespace llvm; #define DEBUG_TYPE "arm-pseudo" diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 61fef1387d82a..480ff4a8c3cb9 100644 --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -572,7 +572,8 @@ class DataFlowSanitizer { const uint64_t NumOfElementsInArgOrgTLS = ArgTLSSize / OriginWidthBytes; public: - DataFlowSanitizer(const std::vector &ABIListFiles); + DataFlowSanitizer(const std::vector &ABIListFiles, + IntrusiveRefCntPtr FS); bool runImpl(Module &M, llvm::function_ref GetTLI); @@ -867,12 +868,11 @@ bool LibAtomicFunction(const Function &F) { } // end anonymous namespace DataFlowSanitizer::DataFlowSanitizer( - const std::vector &ABIListFiles) { + const std::vector &ABIListFiles, + IntrusiveRefCntPtr FS) { std::vector AllABIListFiles(std::move(ABIListFiles)); llvm::append_range(AllABIListFiles, ClABIListFiles); - // FIXME: should we propagate vfs::FileSystem to this constructor? - ABIList.set( - SpecialCaseList::createOrDie(AllABIListFiles, *vfs::getRealFileSystem())); + ABIList.set(SpecialCaseList::createOrDie(AllABIListFiles, *FS)); CombineTaintLookupTableNames.insert_range(ClCombineTaintLookupTables); } @@ -3471,7 +3471,7 @@ PreservedAnalyses DataFlowSanitizerPass::run(Module &M, AM.getResult(M).getManager(); return FAM.getResult(F); }; - if (!DataFlowSanitizer(ABIListFiles).runImpl(M, GetTLI)) + if (!DataFlowSanitizer(ABIListFiles, FS).runImpl(M, GetTLI)) return PreservedAnalyses::all(); PreservedAnalyses PA = PreservedAnalyses::none(); diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp index 7d168a6ceb17c..a32af1d787269 100644 --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -357,27 +357,25 @@ bool llvm::runPassPipeline( bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash, bool EnableDebugify, bool VerifyDIPreserve, bool UnifiedLTO) { - auto FS = vfs::getRealFileSystem(); std::optional P; switch (PGOKindFlag) { case InstrGen: - P = PGOOptions(ProfileFile, "", "", MemoryProfileFile, FS, - PGOOptions::IRInstr, PGOOptions::NoCSAction, - PGOColdFuncAttr); + P = PGOOptions(ProfileFile, "", "", MemoryProfileFile, PGOOptions::IRInstr, + PGOOptions::NoCSAction, PGOColdFuncAttr); break; case InstrUse: - P = PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile, FS, + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile, PGOOptions::IRUse, PGOOptions::NoCSAction, PGOColdFuncAttr); break; case SampleUse: - P = PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile, FS, + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, MemoryProfileFile, PGOOptions::SampleUse, PGOOptions::NoCSAction, PGOColdFuncAttr); break; case NoPGO: if (DebugInfoForProfiling || PseudoProbeForProfiling || !MemoryProfileFile.empty()) - P = PGOOptions("", "", "", MemoryProfileFile, FS, PGOOptions::NoAction, + P = PGOOptions("", "", "", MemoryProfileFile, PGOOptions::NoAction, PGOOptions::NoCSAction, PGOColdFuncAttr, DebugInfoForProfiling, PseudoProbeForProfiling); else @@ -399,7 +397,7 @@ bool llvm::runPassPipeline( P->CSProfileGenFile = CSProfileGenFile; } else P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile, - /*MemoryProfile=*/"", FS, PGOOptions::NoAction, + /*MemoryProfile=*/"", PGOOptions::NoAction, PGOOptions::CSIRInstr); } else /* CSPGOKindFlag == CSInstrUse */ { if (!P) { From 4895353c66ed365109c0beeece4162f2f43b78f8 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 25 Sep 2025 10:40:14 -0700 Subject: [PATCH 18/41] [llvm] Fix X86InstrInfo.cpp build after #160188 --- llvm/lib/Target/X86/X86InstrInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp index abf365eedec39..5e103185fa906 100644 --- a/llvm/lib/Target/X86/X86InstrInfo.cpp +++ b/llvm/lib/Target/X86/X86InstrInfo.cpp @@ -44,6 +44,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" +#include #include using namespace llvm; From 288a4035ad043ac037fc1551d2bd222e8039d71c Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 25 Sep 2025 15:25:08 -0700 Subject: [PATCH 19/41] [clang] Load `-fbasic-block-sections=list=` through the VFS (#160785) This PR loads the path from `-fbasic-block-sections=list=` through the VFS rather than going straight to the real file system. This matches the behavior of other input files of the compiler. --- clang/lib/CodeGen/BackendUtil.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 908b67f4b2f65..d819bbe7e5051 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -447,7 +447,8 @@ static bool initTargetOptions(const CompilerInstance &CI, if (Options.BBSections == llvm::BasicBlockSection::List) { ErrorOr> MBOrErr = - MemoryBuffer::getFile(CodeGenOpts.BBSections.substr(5)); + CI.getVirtualFileSystem().getBufferForFile( + CodeGenOpts.BBSections.substr(5)); if (!MBOrErr) { Diags.Report(diag::err_fe_unable_to_load_basic_block_sections_file) << MBOrErr.getError().message(); From 474fdd423d6142f174280a8234883c7ab9a7cd3c Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 08:17:31 -0700 Subject: [PATCH 20/41] [llvm][clang] Use the VFS in `FileCollector` (#160788) This PR changes `llvm::FileCollector` to use the `llvm::vfs::FileSystem` API for making file paths absolute instead of using `llvm::sys::fs::make_absolute()` directly. This matches the behavior of the compiler on most other input files. --- clang/include/clang/Frontend/Utils.h | 5 +++-- clang/lib/Frontend/CompilerInstance.cpp | 2 +- .../Clang/ModuleDependencyCollector.h | 4 ++-- llvm/include/llvm/Support/FileCollector.h | 8 ++++++- llvm/lib/Support/FileCollector.cpp | 11 +++++----- llvm/tools/dsymutil/Reproducer.cpp | 5 +++-- llvm/unittests/Support/FileCollectorTest.cpp | 21 ++++++++++++------- 7 files changed, 36 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h index 4e76006905f5a..18bf21c147bde 100644 --- a/clang/include/clang/Frontend/Utils.h +++ b/clang/include/clang/Frontend/Utils.h @@ -152,8 +152,9 @@ class ModuleDependencyCollector : public DependencyCollector { std::error_code copyToRoot(StringRef Src, StringRef Dst = {}); public: - ModuleDependencyCollector(std::string DestDir) - : DestDir(std::move(DestDir)) {} + ModuleDependencyCollector(std::string DestDir, + IntrusiveRefCntPtr VFS) + : DestDir(std::move(DestDir)), Canonicalizer(std::move(VFS)) {} ~ModuleDependencyCollector() override { writeFileMap(); } StringRef getDest() { return DestDir; } diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index f9ebecde0d2a1..ddd981d53aee5 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -519,7 +519,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { // then we're the top level compiler instance and need to create one. if (!ModuleDepCollector && !DepOpts.ModuleDependencyOutputDir.empty()) { ModuleDepCollector = std::make_shared( - DepOpts.ModuleDependencyOutputDir); + DepOpts.ModuleDependencyOutputDir, getVirtualFileSystemPtr()); } // If there is a module dep collector, register with other dep collectors diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h index 4fe727460fdb9..dcba0d9c34962 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -19,8 +19,8 @@ class ModuleDependencyCollectorAdaptor public: ModuleDependencyCollectorAdaptor( std::shared_ptr file_collector) - : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) { - } + : clang::ModuleDependencyCollector("", llvm::vfs::getRealFileSystem()), + m_file_collector(file_collector) {} void addFile(llvm::StringRef Filename, llvm::StringRef FileDst = {}) override { diff --git a/llvm/include/llvm/Support/FileCollector.h b/llvm/include/llvm/Support/FileCollector.h index b00bf3174e654..9cc6776b948ba 100644 --- a/llvm/include/llvm/Support/FileCollector.h +++ b/llvm/include/llvm/Support/FileCollector.h @@ -81,19 +81,25 @@ class LLVM_ABI FileCollector : public FileCollectorBase { /// Canonicalize a pair of virtual and real paths. LLVM_ABI PathStorage canonicalize(StringRef SrcPath); + explicit PathCanonicalizer(IntrusiveRefCntPtr VFS) + : VFS(std::move(VFS)) {} + private: /// Replace with a (mostly) real path, or don't modify. Resolves symlinks /// in the directory, using \a CachedDirs to avoid redundant lookups, but /// leaves the filename as a possible symlink. void updateWithRealPath(SmallVectorImpl &Path); + IntrusiveRefCntPtr VFS; + StringMap CachedDirs; }; /// \p Root is the directory where collected files are will be stored. /// \p OverlayRoot is VFS mapping root. /// \p Root directory gets created in copyFiles unless it already exists. - FileCollector(std::string Root, std::string OverlayRoot); + FileCollector(std::string Root, std::string OverlayRoot, + IntrusiveRefCntPtr VFS); /// Write the yaml mapping (for the VFS) to the given file. std::error_code writeMapping(StringRef MappingFile); diff --git a/llvm/lib/Support/FileCollector.cpp b/llvm/lib/Support/FileCollector.cpp index 29436f85c2f23..659d01dbe6caa 100644 --- a/llvm/lib/Support/FileCollector.cpp +++ b/llvm/lib/Support/FileCollector.cpp @@ -49,8 +49,9 @@ static bool isCaseSensitivePath(StringRef Path) { return true; } -FileCollector::FileCollector(std::string Root, std::string OverlayRoot) - : Root(Root), OverlayRoot(OverlayRoot) { +FileCollector::FileCollector(std::string Root, std::string OverlayRoot, + IntrusiveRefCntPtr VFS) + : Root(Root), OverlayRoot(OverlayRoot), Canonicalizer(std::move(VFS)) { assert(sys::path::is_absolute(Root) && "Root not absolute"); assert(sys::path::is_absolute(OverlayRoot) && "OverlayRoot not absolute"); } @@ -88,9 +89,9 @@ void FileCollector::PathCanonicalizer::updateWithRealPath( } /// Make Path absolute. -static void makeAbsolute(SmallVectorImpl &Path) { +static void makeAbsolute(vfs::FileSystem &VFS, SmallVectorImpl &Path) { // We need an absolute src path to append to the root. - sys::fs::make_absolute(Path); + VFS.makeAbsolute(Path); // Canonicalize src to a native path to avoid mixed separator styles. sys::path::native(Path); @@ -105,7 +106,7 @@ FileCollector::PathCanonicalizer::PathStorage FileCollector::PathCanonicalizer::canonicalize(StringRef SrcPath) { PathStorage Paths; Paths.VirtualPath = SrcPath; - makeAbsolute(Paths.VirtualPath); + makeAbsolute(*VFS, Paths.VirtualPath); // If a ".." component is present after a symlink component, remove_dots may // lead to the wrong real destination path. Let the source be canonicalized diff --git a/llvm/tools/dsymutil/Reproducer.cpp b/llvm/tools/dsymutil/Reproducer.cpp index 31e49cdd0518c..0c1d3f90af299 100644 --- a/llvm/tools/dsymutil/Reproducer.cpp +++ b/llvm/tools/dsymutil/Reproducer.cpp @@ -37,9 +37,10 @@ ReproducerGenerate::ReproducerGenerate(std::error_code &EC, int Argc, char **Argv, bool GenerateOnExit) : Root(createReproducerDir(EC)), GenerateOnExit(GenerateOnExit) { llvm::append_range(Args, ArrayRef(Argv, Argc)); + auto RealFS = vfs::getRealFileSystem(); if (!Root.empty()) - FC = std::make_shared(Root, Root); - VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC); + FC = std::make_shared(Root, Root, RealFS); + VFS = FileCollector::createCollectorVFS(std::move(RealFS), FC); } ReproducerGenerate::~ReproducerGenerate() { diff --git a/llvm/unittests/Support/FileCollectorTest.cpp b/llvm/unittests/Support/FileCollectorTest.cpp index 184d0e3fdfd17..0ece86947b4f2 100644 --- a/llvm/unittests/Support/FileCollectorTest.cpp +++ b/llvm/unittests/Support/FileCollectorTest.cpp @@ -43,7 +43,8 @@ class TestingFileCollector : public FileCollector { TEST(FileCollectorTest, addFile) { TempDir root("add_file_root", /*Unique*/ true); std::string root_fs(root.path()); - TestingFileCollector FileCollector(root_fs, root_fs); + TestingFileCollector FileCollector(root_fs, root_fs, + vfs::getRealFileSystem()); FileCollector.addFile("/path/to/a"); FileCollector.addFile("/path/to/b"); @@ -77,7 +78,8 @@ TEST(FileCollectorTest, addDirectory) { TempFile c(ccc.str()); std::string root_fs(file_root.path()); - TestingFileCollector FileCollector(root_fs, root_fs); + TestingFileCollector FileCollector(root_fs, root_fs, + vfs::getRealFileSystem()); FileCollector.addDirectory(file_root.path()); @@ -105,7 +107,8 @@ TEST(FileCollectorTest, copyFiles) { // Create file collector and add files. TempDir root("copy_files_root", /*Unique*/ true); std::string root_fs(root.path()); - TestingFileCollector FileCollector(root_fs, root_fs); + TestingFileCollector FileCollector(root_fs, root_fs, + vfs::getRealFileSystem()); FileCollector.addFile(a.path()); FileCollector.addFile(b.path()); FileCollector.addFile(c.path()); @@ -133,7 +136,8 @@ TEST(FileCollectorTest, recordAndConstructDirectory) { // Create file collector and add files. TempDir root("copy_files_root", /*Unique*/ true); std::string root_fs(root.path()); - TestingFileCollector FileCollector(root_fs, root_fs); + TestingFileCollector FileCollector(root_fs, root_fs, + vfs::getRealFileSystem()); FileCollector.addFile(a.path()); // The empty directory isn't seen until we add it. @@ -169,7 +173,8 @@ TEST(FileCollectorTest, recordVFSAccesses) { // Create file collector and add files. TempDir root("copy_files_root", /*Unique*/ true); std::string root_fs(root.path()); - auto Collector = std::make_shared(root_fs, root_fs); + auto Collector = std::make_shared( + root_fs, root_fs, vfs::getRealFileSystem()); auto VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), Collector); VFS->status(a.path()); @@ -216,7 +221,8 @@ TEST(FileCollectorTest, Symlinks) { // Root where files are copied to. TempDir reproducer_root("reproducer_root", /*Unique*/ true); std::string root_fs(reproducer_root.path()); - TestingFileCollector FileCollector(root_fs, root_fs); + TestingFileCollector FileCollector(root_fs, root_fs, + vfs::getRealFileSystem()); // Add all the files to the collector. FileCollector.addFile(a.path()); @@ -264,7 +270,8 @@ TEST(FileCollectorTest, recordVFSSymlinkAccesses) { // Create file collector and add files. TempDir root("copy_files_root", true); std::string root_fs(root.path()); - auto Collector = std::make_shared(root_fs, root_fs); + auto Collector = std::make_shared( + root_fs, root_fs, vfs::getRealFileSystem()); auto VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), Collector); SmallString<256> Output; From 1ddf29651e001ebe4a43e212217aea3de1bca35d Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 11:28:17 -0700 Subject: [PATCH 21/41] Fix libclang build --- clang/tools/libclang/CDependencies.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/tools/libclang/CDependencies.cpp b/clang/tools/libclang/CDependencies.cpp index 6f765c281c07d..26c8b92435e48 100644 --- a/clang/tools/libclang/CDependencies.cpp +++ b/clang/tools/libclang/CDependencies.cpp @@ -856,11 +856,14 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer( for (const Command &BuildCommand : TU.Commands) PrintArguments(ScriptOS, BuildCommand.Arguments); + auto RealFS = llvm::vfs::getRealFileSystem(); + RealFS->setCurrentWorkingDirectory(*Opts.WorkingDirectory); + SmallString<128> VFSCachePath = FileCachePath; llvm::sys::path::append(VFSCachePath, "vfs"); std::string VFSCachePathStr = VFSCachePath.str().str(); llvm::FileCollector FileCollector(VFSCachePathStr, - /*OverlayRoot=*/VFSCachePathStr); + /*OverlayRoot=*/VFSCachePathStr, RealFS); for (const auto &FileDep : TU.FileDeps) { FileCollector.addFile(FileDep); } From 379220153e95960efeaf19c54b96c2cf2856c486 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 10:35:22 -0700 Subject: [PATCH 22/41] [clang] Load `-fembed-offload-object=` through the VFS (#160906) This PR loads the path from `-fembed-offload-object=` through the VFS rather than going straight to the real file system. This matches the behavior of other input files of the compiler. This technically changes behavior in that `-fembed-offload-object=-` no longer loads the file from stdin, but I don't think that was the intention of the original code anyways. --- clang/include/clang/CodeGen/BackendUtil.h | 2 +- clang/lib/CodeGen/BackendUtil.cpp | 4 ++-- clang/lib/CodeGen/CodeGenAction.cpp | 3 ++- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/CodeGen/BackendUtil.h b/clang/include/clang/CodeGen/BackendUtil.h index bae2798b09f66..9a2b31393735b 100644 --- a/clang/include/clang/CodeGen/BackendUtil.h +++ b/clang/include/clang/CodeGen/BackendUtil.h @@ -52,7 +52,7 @@ void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, llvm::MemoryBufferRef Buf); void EmbedObject(llvm::Module *M, const CodeGenOptions &CGOpts, - DiagnosticsEngine &Diags); + llvm::vfs::FileSystem &VFS, DiagnosticsEngine &Diags); } // namespace clang #endif diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index d819bbe7e5051..fd9f6f4db5958 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1509,13 +1509,13 @@ void clang::EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, } void clang::EmbedObject(llvm::Module *M, const CodeGenOptions &CGOpts, - DiagnosticsEngine &Diags) { + llvm::vfs::FileSystem &VFS, DiagnosticsEngine &Diags) { if (CGOpts.OffloadObjects.empty()) return; for (StringRef OffloadObject : CGOpts.OffloadObjects) { llvm::ErrorOr> ObjectOrErr = - llvm::MemoryBuffer::getFileOrSTDIN(OffloadObject); + VFS.getBufferForFile(OffloadObject); if (ObjectOrErr.getError()) { auto DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "could not open '%0' for embedding"); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 892db0014fe83..61ae1cdcb1395 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -1160,7 +1160,8 @@ void CodeGenAction::ExecuteAction() { TheModule->setTargetTriple(Triple(TargetOpts.Triple)); } - EmbedObject(TheModule.get(), CodeGenOpts, Diagnostics); + EmbedObject(TheModule.get(), CodeGenOpts, CI.getVirtualFileSystem(), + Diagnostics); EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile); LLVMContext &Ctx = TheModule->getContext(); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 54a4fdfd11456..16d209b1b05b2 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1566,7 +1566,7 @@ void CodeGenModule::Release() { EmitBackendOptionsMetadata(getCodeGenOpts()); // If there is device offloading code embed it in the host now. - EmbedObject(&getModule(), CodeGenOpts, getDiags()); + EmbedObject(&getModule(), CodeGenOpts, *getFileSystem(), getDiags()); // Set visibility from DLL storage class // We do this at the end of LLVM IR generation; after any operation From e625afe94ec010fdca5fbc50560d65210b26dcb2 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 12:25:37 -0700 Subject: [PATCH 23/41] [clang] Use the VFS to create the OpenMP region entry ID (#160918) This PR uses the VFS to create the OpenMP target entry instead of going straight to the real file system. This matches the behavior of other input files of the compiler. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 3 ++- llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h | 2 +- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp | 14 ++++++++------ .../Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp | 16 ++++++++++------ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index c6b5620c40b84..86b2259056842 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1547,7 +1547,8 @@ static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc( return std::pair(PLoc.getFilename(), PLoc.getLine()); }; - return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack, ParentName); + return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack, + *CGM.getFileSystem(), ParentName); } ConstantAddress CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h index 584af21049908..21f4a9ef313c0 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -1350,7 +1350,7 @@ class OpenMPIRBuilder { /// any. LLVM_ABI static TargetRegionEntryInfo getTargetEntryUniqueInfo(FileIdentifierInfoCallbackTy CallBack, - StringRef ParentName = ""); + vfs::FileSystem &VFS, StringRef ParentName = ""); /// Enum class for the RedctionGen CallBack type to be used. enum class ReductionGenCBKind { Clang, MLIR }; diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 39862335198c7..3dbbe8dec26cd 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -9849,17 +9849,19 @@ void OffloadEntriesInfoManager::getTargetRegionEntryFnName( TargetRegionEntryInfo OpenMPIRBuilder::getTargetEntryUniqueInfo(FileIdentifierInfoCallbackTy CallBack, + vfs::FileSystem &VFS, StringRef ParentName) { sys::fs::UniqueID ID(0xdeadf17e, 0); auto FileIDInfo = CallBack(); uint64_t FileID = 0; - std::error_code EC = sys::fs::getUniqueID(std::get<0>(FileIDInfo), ID); - // If the inode ID could not be determined, create a hash value - // the current file name and use that as an ID. - if (EC) + if (ErrorOr Status = VFS.status(std::get<0>(FileIDInfo))) { + ID = Status->getUniqueID(); + FileID = Status->getUniqueID().getFile(); + } else { + // If the inode ID could not be determined, create a hash value + // the current file name and use that as an ID. FileID = hash_value(std::get<0>(FileIDInfo)); - else - FileID = ID.getFile(); + } return TargetRegionEntryInfo(ParentName, ID.getDevice(), FileID, std::get<1>(FileIDInfo)); diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index 0dbe28f991b3c..e8a057b686c61 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -3534,8 +3534,10 @@ getDeclareTargetRefPtrSuffix(LLVM::GlobalOp globalOp, llvm::StringRef(loc.getFilename()), loc.getLine()); }; + auto vfs = llvm::vfs::getRealFileSystem(); os << llvm::format( - "_%x", ompBuilder.getTargetEntryUniqueInfo(fileInfoCallBack).FileID); + "_%x", + ompBuilder.getTargetEntryUniqueInfo(fileInfoCallBack, *vfs).FileID); } os << "_decl_tgt_ref_ptr"; @@ -5809,10 +5811,12 @@ convertDeclareTargetAttr(Operation *op, mlir::omp::DeclareTargetAttr attribute, lineNo); }; + auto vfs = llvm::vfs::getRealFileSystem(); + ompBuilder->registerTargetGlobalVariable( captureClause, deviceClause, isDeclaration, isExternallyVisible, - ompBuilder->getTargetEntryUniqueInfo(fileInfoCallBack), mangledName, - generatedRefs, /*OpenMPSimd*/ false, targetTriple, + ompBuilder->getTargetEntryUniqueInfo(fileInfoCallBack, *vfs), + mangledName, generatedRefs, /*OpenMPSimd*/ false, targetTriple, /*GlobalInitializer*/ nullptr, /*VariableLinkage*/ nullptr, gVal->getType(), gVal); @@ -5822,9 +5826,9 @@ convertDeclareTargetAttr(Operation *op, mlir::omp::DeclareTargetAttr attribute, ompBuilder->Config.hasRequiresUnifiedSharedMemory())) { ompBuilder->getAddrOfDeclareTargetVar( captureClause, deviceClause, isDeclaration, isExternallyVisible, - ompBuilder->getTargetEntryUniqueInfo(fileInfoCallBack), mangledName, - generatedRefs, /*OpenMPSimd*/ false, targetTriple, gVal->getType(), - /*GlobalInitializer*/ nullptr, + ompBuilder->getTargetEntryUniqueInfo(fileInfoCallBack, *vfs), + mangledName, generatedRefs, /*OpenMPSimd*/ false, targetTriple, + gVal->getType(), /*GlobalInitializer*/ nullptr, /*VariableLinkage*/ nullptr); } } From 6a362a6d2a28ae6f907e7756b567967e4d9ab0fc Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 14:53:29 -0700 Subject: [PATCH 24/41] [clang] Use the VFS to check the system framework marker (#160946) This PR uses the VFS/`FileManager` to check the system framework marker instead of going straight to the real file system. This matches the behavior of other input files of the compiler. --- clang/lib/Lex/HeaderSearch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index bede2c8ead049..39b8fe3e0bd8d 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -672,9 +672,8 @@ OptionalFileEntryRef DirectoryLookup::DoFrameworkLookup( if (getDirCharacteristic() == SrcMgr::C_User) { SmallString<1024> SystemFrameworkMarker(FrameworkName); SystemFrameworkMarker += ".system_framework"; - if (llvm::sys::fs::exists(SystemFrameworkMarker)) { + if (FileMgr.getOptionalFileRef(SystemFrameworkMarker)) CacheEntry.IsUserSpecifiedSystemFramework = true; - } } } From 06b40a378c0c524b3ff3355cbce87139a77d6d3f Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 14:53:46 -0700 Subject: [PATCH 25/41] [clang][analyzer] Use the VFS to check model files (#160950) This PR uses the VFS to check `.model` files in the Clang static analyzer to match the compiler's behavior for other input files. --- clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index 51e23a3b4ac6a..f2a05f835396d 100644 --- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -65,7 +65,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { else fileName = llvm::StringRef(D->getName().str() + ".model"); - if (!llvm::sys::fs::exists(fileName.str())) { + if (!CI.getVirtualFileSystem().exists(fileName)) { Bodies[D->getName()] = nullptr; return; } From 1c8b036a7ba59eac78c01c10f36b50916e263c6d Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 14:54:03 -0700 Subject: [PATCH 26/41] [clang] Use the VFS to get the unique file ID (#160936) This PR uses the VFS to get the unique file ID when printing externalized decls in CUDA instead of going straight to the real file system. This matches the behavior of other input files of the compiler. --- clang/lib/CodeGen/CodeGenModule.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 16d209b1b05b2..3898d8121b18b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -8116,12 +8116,17 @@ void CodeGenModule::printPostfixForExternalizedDecl(llvm::raw_ostream &OS, // Get the UniqueID for the file containing the decl. llvm::sys::fs::UniqueID ID; - if (llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { + auto Status = FS->status(PLoc.getFilename()); + if (!Status) { PLoc = SM.getPresumedLoc(D->getLocation(), /*UseLineDirectives=*/false); assert(PLoc.isValid() && "Source location is expected to be valid."); - if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) - SM.getDiagnostics().Report(diag::err_cannot_open_file) - << PLoc.getFilename() << EC.message(); + Status = FS->status(PLoc.getFilename()); + } + if (!Status) { + SM.getDiagnostics().Report(diag::err_cannot_open_file) + << PLoc.getFilename() << Status.getError().message(); + } else { + ID = Status->getUniqueID(); } OS << llvm::format("%x", ID.getFile()) << llvm::format("%x", ID.getDevice()) << "_" << llvm::utohexstr(Result.low(), /*LowerCase=*/true, /*Width=*/8); From fbb26afe68a809e7abf90a3e9aa6b01fd6077816 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Fri, 26 Sep 2025 14:54:18 -0700 Subject: [PATCH 27/41] [clang] Use the VFS to get the OpenMP entry info (#160935) This PR uses the VFS to get the OpenMP entry info instead of going straight to the real file system. This matches the behavior of other input files of the compiler. --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 86b2259056842..cb73cb49d1e26 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1539,10 +1539,8 @@ static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc( SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(BeginLoc); - llvm::sys::fs::UniqueID ID; - if (llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { + if (CGM.getFileSystem()->exists(PLoc.getFilename())) PLoc = SM.getPresumedLoc(BeginLoc, /*UseLineDirectives=*/false); - } return std::pair(PLoc.getFilename(), PLoc.getLine()); }; From f3441b0a16f8859d34a7f413b2786be8b01930ce Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 29 Sep 2025 09:00:37 -0700 Subject: [PATCH 28/41] [llvm] Use the VFS to get the real path in `FileCollector` (#160943) This PR starts using the correct VFS for getting file's real path in `FileCollector` instead of using the real FS directly. This matches compiler's behavior for other input files. --- llvm/lib/Support/FileCollector.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Support/FileCollector.cpp b/llvm/lib/Support/FileCollector.cpp index 659d01dbe6caa..bf236171c1cf3 100644 --- a/llvm/lib/Support/FileCollector.cpp +++ b/llvm/lib/Support/FileCollector.cpp @@ -68,9 +68,8 @@ void FileCollector::PathCanonicalizer::updateWithRealPath( SmallString<256> RealPath; auto DirWithSymlink = CachedDirs.find(Directory); if (DirWithSymlink == CachedDirs.end()) { - // FIXME: Should this be a call to FileSystem::getRealpath(), in some - // cases? What if there is nothing on disk? - if (sys::fs::real_path(Directory, RealPath)) + // FIXME: What if there is nothing on disk? + if (VFS->getRealPath(Directory, RealPath)) return; CachedDirs[Directory] = std::string(RealPath); } else { From 81ea7163b185d6da6c1ea05719cde04015933c38 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 29 Sep 2025 09:38:49 -0700 Subject: [PATCH 29/41] [clang] Use the VFS in `ModuleDependencyCollector` (#160944) This PR starts using the correct VFS in `ModuleDependencyCollector` instead of using the real FS directly. This matches compiler's behavior for other input files. --- clang/lib/Frontend/ModuleDependencyCollector.cpp | 11 ++++++----- llvm/include/llvm/Support/FileCollector.h | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/clang/lib/Frontend/ModuleDependencyCollector.cpp b/clang/lib/Frontend/ModuleDependencyCollector.cpp index 3b363f948a3a8..ff37065885289 100644 --- a/clang/lib/Frontend/ModuleDependencyCollector.cpp +++ b/clang/lib/Frontend/ModuleDependencyCollector.cpp @@ -91,10 +91,10 @@ void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) { std::make_unique(*this)); } -static bool isCaseSensitivePath(StringRef Path) { +static bool isCaseSensitivePath(llvm::vfs::FileSystem &VFS, StringRef Path) { SmallString<256> TmpDest = Path, UpperDest, RealDest; // Remove component traversals, links, etc. - if (llvm::sys::fs::real_path(Path, TmpDest)) + if (VFS.getRealPath(Path, TmpDest)) return true; // Current default value in vfs.yaml Path = TmpDest; @@ -104,7 +104,7 @@ static bool isCaseSensitivePath(StringRef Path) { // already expects when sensitivity isn't setup. for (auto &C : Path) UpperDest.push_back(toUppercase(C)); - if (!llvm::sys::fs::real_path(UpperDest, RealDest) && Path == RealDest) + if (!VFS.getRealPath(UpperDest, RealDest) && Path == RealDest) return false; return true; } @@ -121,7 +121,8 @@ void ModuleDependencyCollector::writeFileMap() { // Explicitly set case sensitivity for the YAML writer. For that, find out // the sensitivity at the path where the headers all collected to. - VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir)); + VFSWriter.setCaseSensitivity( + isCaseSensitivePath(Canonicalizer.getFileSystem(), VFSDir)); // Do not rely on real path names when executing the crash reproducer scripts // since we only want to actually use the files we have on the VFS cache. @@ -153,7 +154,7 @@ std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src, } else { // When collecting entries from input vfsoverlays, copy the external // contents into the cache but still map from the source. - if (!fs::exists(Dst)) + if (!Canonicalizer.getFileSystem().exists(Dst)) return std::error_code(); path::append(CacheDst, Dst); Paths.CopyFrom = Dst; diff --git a/llvm/include/llvm/Support/FileCollector.h b/llvm/include/llvm/Support/FileCollector.h index 9cc6776b948ba..9fa11ba362241 100644 --- a/llvm/include/llvm/Support/FileCollector.h +++ b/llvm/include/llvm/Support/FileCollector.h @@ -81,6 +81,9 @@ class LLVM_ABI FileCollector : public FileCollectorBase { /// Canonicalize a pair of virtual and real paths. LLVM_ABI PathStorage canonicalize(StringRef SrcPath); + /// Return the underlying file system. + vfs::FileSystem &getFileSystem() const { return *VFS; }; + explicit PathCanonicalizer(IntrusiveRefCntPtr VFS) : VFS(std::move(VFS)) {} From 971a04ee92e0b0ecb5cbd810fba463ee26a02e8c Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 29 Sep 2025 10:01:10 -0700 Subject: [PATCH 30/41] [llvm] Use the underlying VFS when constructing `RedirectingFileSystem` (#160942) When the root node of the `RedirectingFileSystem` is to be resolved to the current working directory, we previously consulted the real FS instead of the provided underlying VFS. This PR fixes that issue. --- llvm/lib/Support/VirtualFileSystem.cpp | 2 +- .../Support/VirtualFileSystemTest.cpp | 32 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index afcfcc7d3f4c3..7bc749021d301 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1992,7 +1992,7 @@ class llvm::vfs::RedirectingFileSystemParser { EC = FS->makeAbsolute(FullPath, Name); Name = canonicalize(Name); } else { - EC = sys::fs::make_absolute(Name); + EC = FS->makeAbsolute(Name); } if (EC) { assert(NameValueNode && "Name presence should be checked earlier"); diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index c150d12338b1f..f708e0e901408 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -1954,7 +1954,7 @@ TEST_F(VFSFromYAMLTest, ReturnsExternalPathVFSHit) { EXPECT_EQ(0, NumDiagnostics); } -TEST_F(VFSFromYAMLTest, RootRelativeTest) { +TEST_F(VFSFromYAMLTest, RootRelativeToOverlayDirTest) { IntrusiveRefCntPtr Lower(new DummyFileSystem()); Lower->addDirectory("//root/foo/bar"); Lower->addRegularFile("//root/foo/bar/a"); @@ -2017,6 +2017,35 @@ TEST_F(VFSFromYAMLTest, RootRelativeTest) { #endif } +TEST_F(VFSFromYAMLTest, RootRelativeToCWDTest) { + auto Lower = makeIntrusiveRefCnt(); + Lower->addDirectory("//root/foo/bar"); + Lower->addRegularFile("//root/foo/bar/a"); + Lower->addDirectory("//root/foo/bar/cwd"); + Lower->addRegularFile("//root/foo/bar/cwd/a"); + Lower->setCurrentWorkingDirectory("//root/foo/bar/cwd"); + IntrusiveRefCntPtr FS = + getFromYAMLString("{\n" + " 'case-sensitive': false,\n" + " 'root-relative': 'cwd',\n" + " 'roots': [\n" + " { 'name': 'b', 'type': 'file',\n" + " 'external-contents': '//root/foo/bar/a'\n" + " }\n" + " ]\n" + "}", + Lower, "//root/foo/bar/overlay"); + + ASSERT_NE(FS.get(), nullptr); + + ErrorOr S1 = FS->status("//root/foo/bar/b"); + ASSERT_TRUE(S1.getError()); + + ErrorOr S2 = FS->status("//root/foo/bar/cwd/b"); + ASSERT_FALSE(S2.getError()); + EXPECT_EQ("//root/foo/bar/a", S2->getName()); +} + TEST_F(VFSFromYAMLTest, ReturnsInternalPathVFSHit) { IntrusiveRefCntPtr BaseFS( new vfs::InMemoryFileSystem); @@ -2508,6 +2537,7 @@ TEST_F(VFSFromYAMLTest, RelativePaths) { SmallString<128> CWD; EC = llvm::sys::fs::current_path(CWD); ASSERT_FALSE(EC); + Lower->setCurrentWorkingDirectory(CWD); // Filename at root level without a parent directory. IntrusiveRefCntPtr FS = getFromYAMLString( From fe90297596b61aa1c3ab8fdc90dbd6e41c28d8c0 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 29 Sep 2025 14:37:18 -0700 Subject: [PATCH 31/41] [llvm][clang] Use the VFS in `GCOVProfilerPass` (#161260) This PR starts using the correct VFS in `GCOVProfilerPass` instead of using the real FS directly. This matches compiler's behavior for other input files. --- clang/lib/CodeGen/BackendUtil.cpp | 5 ++-- .../Transforms/Instrumentation/GCOVProfiler.h | 6 +++- .../Instrumentation/GCOVProfiling.cpp | 30 +++++++++++-------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index fd9f6f4db5958..0f9129d1575a4 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1121,8 +1121,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (std::optional Options = getGCOVOptions(CodeGenOpts, LangOpts)) PB.registerPipelineStartEPCallback( - [Options](ModulePassManager &MPM, OptimizationLevel Level) { - MPM.addPass(GCOVProfilerPass(*Options)); + [this, Options](ModulePassManager &MPM, OptimizationLevel Level) { + MPM.addPass( + GCOVProfilerPass(*Options, CI.getVirtualFileSystemPtr())); }); if (std::optional Options = getInstrProfOptions(CodeGenOpts, LangOpts)) diff --git a/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h b/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h index 4d3ead29af0d2..f53cee26739a4 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h +++ b/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h @@ -20,11 +20,15 @@ namespace llvm { /// The gcov-style instrumentation pass class GCOVProfilerPass : public PassInfoMixin { public: - GCOVProfilerPass(const GCOVOptions &Options = GCOVOptions::getDefault()) : GCOVOpts(Options) { } + GCOVProfilerPass( + const GCOVOptions &Options = GCOVOptions::getDefault(), + IntrusiveRefCntPtr VFS = vfs::getRealFileSystem()) + : GCOVOpts(Options), VFS(std::move(VFS)) {} LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); private: GCOVOptions GCOVOpts; + IntrusiveRefCntPtr VFS; }; } // namespace llvm diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp index e5bf2d1187a89..d8422755c28b8 100644 --- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation/CFGMST.h" #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" @@ -92,8 +93,10 @@ class GCOVFunction; class GCOVProfiler { public: - GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} - GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {} + GCOVProfiler() + : GCOVProfiler(GCOVOptions::getDefault(), *vfs::getRealFileSystem()) {} + GCOVProfiler(const GCOVOptions &Opts, vfs::FileSystem &VFS) + : Options(Opts), VFS(VFS) {} bool runOnModule(Module &M, function_ref GetBFI, function_ref GetBPI, @@ -110,6 +113,7 @@ class GCOVProfiler { os->write_zeros(4 - s.size() % 4); } void writeBytes(const char *Bytes, int Size) { os->write(Bytes, Size); } + vfs::FileSystem &getVirtualFileSystem() const { return VFS; } private: // Create the .gcno files for the Module based on DebugInfo. @@ -166,6 +170,7 @@ class GCOVProfiler { std::vector ExcludeRe; DenseSet ExecBlocks; StringMap InstrumentedFiles; + vfs::FileSystem &VFS; }; struct BBInfo { @@ -214,10 +219,10 @@ static StringRef getFunctionName(const DISubprogram *SP) { /// Prefer relative paths in the coverage notes. Clang also may split /// up absolute paths into a directory and filename component. When /// the relative path doesn't exist, reconstruct the absolute path. -static SmallString<128> getFilename(const DIScope *SP) { +static SmallString<128> getFilename(const DIScope *SP, vfs::FileSystem &VFS) { SmallString<128> Path; StringRef RelPath = SP->getFilename(); - if (sys::fs::exists(RelPath)) + if (VFS.exists(RelPath)) Path = RelPath; else sys::path::append(Path, SP->getDirectory(), SP->getFilename()); @@ -357,7 +362,7 @@ namespace { void writeOut(uint32_t CfgChecksum) { write(GCOV_TAG_FUNCTION); - SmallString<128> Filename = getFilename(SP); + SmallString<128> Filename = getFilename(SP, P->getVirtualFileSystem()); uint32_t BlockLen = 3 + wordsOfString(getFunctionName(SP)); BlockLen += 1 + wordsOfString(Filename) + 4; @@ -455,7 +460,7 @@ bool GCOVProfiler::isFunctionInstrumented(const Function &F) { if (FilterRe.empty() && ExcludeRe.empty()) { return true; } - SmallString<128> Filename = getFilename(F.getSubprogram()); + SmallString<128> Filename = getFilename(F.getSubprogram(), VFS); auto It = InstrumentedFiles.find(Filename); if (It != InstrumentedFiles.end()) { return It->second; @@ -467,7 +472,7 @@ bool GCOVProfiler::isFunctionInstrumented(const Function &F) { // Path can be // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for // such a case we must get the real_path. - if (sys::fs::real_path(Filename, RealPath)) { + if (VFS.getRealPath(Filename, RealPath)) { // real_path can fail with path like "foo.c". RealFilename = Filename; } else { @@ -524,9 +529,10 @@ std::string GCOVProfiler::mangleName(const DICompileUnit *CU, SmallString<128> Filename = CU->getFilename(); sys::path::replace_extension(Filename, Notes ? "gcno" : "gcda"); StringRef FName = sys::path::filename(Filename); - SmallString<128> CurPath; - if (sys::fs::current_path(CurPath)) + ErrorOr CWD = VFS.getCurrentWorkingDirectory(); + if (!CWD) return std::string(FName); + SmallString<128> CurPath{*CWD}; sys::path::append(CurPath, FName); return std::string(CurPath); } @@ -554,7 +560,7 @@ bool GCOVProfiler::runOnModule( PreservedAnalyses GCOVProfilerPass::run(Module &M, ModuleAnalysisManager &AM) { - GCOVProfiler Profiler(GCOVOpts); + GCOVProfiler Profiler(GCOVOpts, *VFS); FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); @@ -789,7 +795,7 @@ bool GCOVProfiler::emitProfileNotes( // Add the function line number to the lines of the entry block // to have a counter for the function definition. uint32_t Line = SP->getLine(); - auto Filename = getFilename(SP); + auto Filename = getFilename(SP, VFS); BranchProbabilityInfo *BPI = GetBPI(F); BlockFrequencyInfo *BFI = GetBFI(F); @@ -881,7 +887,7 @@ bool GCOVProfiler::emitProfileNotes( if (SP != getDISubprogram(Scope)) continue; - GCOVLines &Lines = Block.getFile(getFilename(Loc->getScope())); + GCOVLines &Lines = Block.getFile(getFilename(Loc->getScope(), VFS)); Lines.addLine(Loc.getLine()); } Line = 0; From b22814511143262305611fb5f2bb3488831ee574 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 30 Sep 2025 10:36:21 -0700 Subject: [PATCH 32/41] [llvm] Use the VFS to make path absolute (#161271) For the redirecting VFS, the `'overlay-relative'` option controls whether external paths should be appended to the overlay directory. This didn't always work as expected: when the overlay file path itself was relative, its absolute path was decided by the real FS, not the underlying VFS, and the resulting external path didn't exist in the underlying VFS. This PR fixes this issue. --- llvm/lib/Support/VirtualFileSystem.cpp | 9 ++++++-- .../Support/VirtualFileSystemTest.cpp | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 7bc749021d301..8685b096dcd62 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1927,7 +1927,12 @@ class llvm::vfs::RedirectingFileSystemParser { FullPath = FS->getOverlayFileDir(); assert(!FullPath.empty() && "External contents prefix directory must exist"); - llvm::sys::path::append(FullPath, Value); + SmallString<256> AbsFullPath = Value; + if (FS->makeAbsolute(FullPath, AbsFullPath)) { + error(N, "failed to make 'external-contents' absolute"); + return nullptr; + } + FullPath = AbsFullPath; } else { FullPath = Value; } @@ -2223,7 +2228,7 @@ RedirectingFileSystem::create(std::unique_ptr Buffer, // FS->OverlayFileDir => //dummy.cache/vfs // SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath); - std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir); + std::error_code EC = FS->makeAbsolute(OverlayAbsDir); assert(!EC && "Overlay dir final path must be absolute"); (void)EC; FS->setOverlayFileDir(OverlayAbsDir); diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index f708e0e901408..e740784cb9acd 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -1954,6 +1954,29 @@ TEST_F(VFSFromYAMLTest, ReturnsExternalPathVFSHit) { EXPECT_EQ(0, NumDiagnostics); } +TEST_F(VFSFromYAMLTest, RelativeFileDirWithOverlayRelativeSetting) { + auto Lower = makeIntrusiveRefCnt(); + Lower->addDirectory("//root/foo/bar"); + Lower->addRegularFile("//root/foo/bar/a"); + Lower->setCurrentWorkingDirectory("//root/foo"); + IntrusiveRefCntPtr FS = + getFromYAMLString("{\n" + " 'case-sensitive': false,\n" + " 'overlay-relative': true,\n" + " 'roots': [\n" + " { 'name': '//root/foo/bar/b', 'type': 'file',\n" + " 'external-contents': 'a'\n" + " }\n" + " ]\n" + "}", + Lower, "bar/overlay"); + + ASSERT_NE(FS.get(), nullptr); + ErrorOr S = FS->status("//root/foo/bar/b"); + ASSERT_FALSE(S.getError()); + EXPECT_EQ("//root/foo/bar/a", S->getName()); +} + TEST_F(VFSFromYAMLTest, RootRelativeToOverlayDirTest) { IntrusiveRefCntPtr Lower(new DummyFileSystem()); Lower->addDirectory("//root/foo/bar"); From 18e67731a4f32bea40278b81beb1a635ca0507ee Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 30 Sep 2025 10:38:07 -0700 Subject: [PATCH 33/41] [llvm] Fix build after #161260 The modular build was failing due to a missing include. --- llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h b/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h index f53cee26739a4..43ef86b08517a 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h +++ b/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h @@ -14,6 +14,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Transforms/Utils/Instrumentation.h" namespace llvm { From 8f6ed3a7bed337f3a2c563c7d6bd36f37532f79b Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Tue, 30 Sep 2025 10:46:21 -0700 Subject: [PATCH 34/41] [clang][modules] Virtualize module cache pruning (#149113) This PR virtualizes module cache pruning via the new `ModuleCache` interface. Currently this is an NFC, but I left a FIXME in `InProcessModuleCache` to make this more efficient for the dependency scanner. --- .../include/clang/Serialization/ModuleCache.h | 9 +- clang/lib/Frontend/CompilerInstance.cpp | 93 +------------------ clang/lib/Serialization/ModuleCache.cpp | 86 +++++++++++++++++ .../InProcessModuleCache.cpp | 7 ++ 4 files changed, 105 insertions(+), 90 deletions(-) diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h index 3117d954a09cc..ec052c5c18e0a 100644 --- a/clang/include/clang/Serialization/ModuleCache.h +++ b/clang/include/clang/Serialization/ModuleCache.h @@ -45,11 +45,15 @@ class ModuleCache : public RefCountedBase { /// were validated. virtual void updateModuleTimestamp(StringRef ModuleFilename) = 0; + /// Prune module files that haven't been accessed in a long time. + virtual void maybePrune(StringRef Path, time_t PruneInterval, + time_t PruneAfter) = 0; + /// Returns this process's view of the module cache. virtual InMemoryModuleCache &getInMemoryModuleCache() = 0; virtual const InMemoryModuleCache &getInMemoryModuleCache() const = 0; - // TODO: Virtualize writing/reading PCM files, pruning, etc. + // TODO: Virtualize writing/reading PCM files, etc. virtual ~ModuleCache() = default; }; @@ -59,6 +63,9 @@ class ModuleCache : public RefCountedBase { /// \c CompilerInstance instances participating in building modules for single /// translation unit in order to share the same \c InMemoryModuleCache. IntrusiveRefCntPtr createCrossProcessModuleCache(); + +/// Shared implementation of `ModuleCache::maybePrune()`. +void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter); } // namespace clang #endif diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index ddd981d53aee5..3ea4fc25673ab 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1848,90 +1848,6 @@ static void checkConfigMacros(Preprocessor &PP, Module *M, } } -/// Write a new timestamp file with the given path. -static void writeTimestampFile(StringRef TimestampFile) { - std::error_code EC; - llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::OF_None); -} - -/// Prune the module cache of modules that haven't been accessed in -/// a long time. -static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { - llvm::sys::fs::file_status StatBuf; - llvm::SmallString<128> TimestampFile; - TimestampFile = HSOpts.ModuleCachePath; - assert(!TimestampFile.empty()); - llvm::sys::path::append(TimestampFile, "modules.timestamp"); - - // Try to stat() the timestamp file. - if (std::error_code EC = llvm::sys::fs::status(TimestampFile, StatBuf)) { - // If the timestamp file wasn't there, create one now. - if (EC == std::errc::no_such_file_or_directory) { - writeTimestampFile(TimestampFile); - } - return; - } - - // Check whether the time stamp is older than our pruning interval. - // If not, do nothing. - time_t TimeStampModTime = - llvm::sys::toTimeT(StatBuf.getLastModificationTime()); - time_t CurrentTime = time(nullptr); - if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval)) - return; - - // Write a new timestamp file so that nobody else attempts to prune. - // There is a benign race condition here, if two Clang instances happen to - // notice at the same time that the timestamp is out-of-date. - writeTimestampFile(TimestampFile); - - // Walk the entire module cache, looking for unused module files and module - // indices. - std::error_code EC; - for (llvm::sys::fs::directory_iterator Dir(HSOpts.ModuleCachePath, EC), - DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { - // If we don't have a directory, there's nothing to look into. - if (!llvm::sys::fs::is_directory(Dir->path())) - continue; - - // Walk all of the files within this directory. - for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd; - File != FileEnd && !EC; File.increment(EC)) { - // We only care about module and global module index files. - StringRef Extension = llvm::sys::path::extension(File->path()); - if (Extension != ".pcm" && Extension != ".timestamp" && - llvm::sys::path::filename(File->path()) != "modules.idx") - continue; - - // Look at this file. If we can't stat it, there's nothing interesting - // there. - if (llvm::sys::fs::status(File->path(), StatBuf)) - continue; - - // If the file has been used recently enough, leave it there. - time_t FileAccessTime = llvm::sys::toTimeT(StatBuf.getLastAccessedTime()); - if (CurrentTime - FileAccessTime <= - time_t(HSOpts.ModuleCachePruneAfter)) { - continue; - } - - // Remove the file. - llvm::sys::fs::remove(File->path()); - - // Remove the timestamp file. - std::string TimpestampFilename = File->path() + ".timestamp"; - llvm::sys::fs::remove(TimpestampFilename); - } - - // If we removed all of the files in the directory, remove the directory - // itself. - if (llvm::sys::fs::directory_iterator(Dir->path(), EC) == - llvm::sys::fs::directory_iterator() && !EC) - llvm::sys::fs::remove(Dir->path()); - } -} - void CompilerInstance::createASTReader() { if (TheASTReader) return; @@ -1942,11 +1858,10 @@ void CompilerInstance::createASTReader() { // If we're implicitly building modules but not currently recursively // building a module, check whether we need to prune the module cache. if (getSourceManager().getModuleBuildStack().empty() && - !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty() && - getHeaderSearchOpts().ModuleCachePruneInterval > 0 && - getHeaderSearchOpts().ModuleCachePruneAfter > 0) { - pruneModuleCache(getHeaderSearchOpts()); - } + !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty()) + ModCache->maybePrune(getHeaderSearchOpts().ModuleCachePath, + getHeaderSearchOpts().ModuleCachePruneInterval, + getHeaderSearchOpts().ModuleCachePruneAfter); HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); std::string Sysroot = HSOpts.Sysroot; diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp index 88ad8dd6495dd..9850956380423 100644 --- a/clang/lib/Serialization/ModuleCache.cpp +++ b/clang/lib/Serialization/ModuleCache.cpp @@ -16,6 +16,87 @@ using namespace clang; +/// Write a new timestamp file with the given path. +static void writeTimestampFile(StringRef TimestampFile) { + std::error_code EC; + llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::OF_None); +} + +void clang::maybePruneImpl(StringRef Path, time_t PruneInterval, + time_t PruneAfter) { + if (PruneInterval <= 0 || PruneAfter <= 0) + return; + + llvm::SmallString<128> TimestampFile(Path); + llvm::sys::path::append(TimestampFile, "modules.timestamp"); + + // Try to stat() the timestamp file. + llvm::sys::fs::file_status StatBuf; + if (std::error_code EC = llvm::sys::fs::status(TimestampFile, StatBuf)) { + // If the timestamp file wasn't there, create one now. + if (EC == std::errc::no_such_file_or_directory) + writeTimestampFile(TimestampFile); + return; + } + + // Check whether the time stamp is older than our pruning interval. + // If not, do nothing. + time_t TimestampModTime = + llvm::sys::toTimeT(StatBuf.getLastModificationTime()); + time_t CurrentTime = time(nullptr); + if (CurrentTime - TimestampModTime <= PruneInterval) + return; + + // Write a new timestamp file so that nobody else attempts to prune. + // There is a benign race condition here, if two Clang instances happen to + // notice at the same time that the timestamp is out-of-date. + writeTimestampFile(TimestampFile); + + // Walk the entire module cache, looking for unused module files and module + // indices. + std::error_code EC; + for (llvm::sys::fs::directory_iterator Dir(Path, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // If we don't have a directory, there's nothing to look into. + if (!llvm::sys::fs::is_directory(Dir->path())) + continue; + + // Walk all the files within this directory. + for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd; + File != FileEnd && !EC; File.increment(EC)) { + // We only care about module and global module index files. + StringRef Extension = llvm::sys::path::extension(File->path()); + if (Extension != ".pcm" && Extension != ".timestamp" && + llvm::sys::path::filename(File->path()) != "modules.idx") + continue; + + // Look at this file. If we can't stat it, there's nothing interesting + // there. + if (llvm::sys::fs::status(File->path(), StatBuf)) + continue; + + // If the file has been used recently enough, leave it there. + time_t FileAccessTime = llvm::sys::toTimeT(StatBuf.getLastAccessedTime()); + if (CurrentTime - FileAccessTime <= PruneAfter) + continue; + + // Remove the file. + llvm::sys::fs::remove(File->path()); + + // Remove the timestamp file. + std::string TimpestampFilename = File->path() + ".timestamp"; + llvm::sys::fs::remove(TimpestampFilename); + } + + // If we removed all the files in the directory, remove the directory + // itself. + if (llvm::sys::fs::directory_iterator(Dir->path(), EC) == + llvm::sys::fs::directory_iterator() && + !EC) + llvm::sys::fs::remove(Dir->path()); + } +} + namespace { class CrossProcessModuleCache : public ModuleCache { InMemoryModuleCache InMemory; @@ -55,6 +136,11 @@ class CrossProcessModuleCache : public ModuleCache { OS.clear_error(); // Avoid triggering a fatal error. } + void maybePrune(StringRef Path, time_t PruneInterval, + time_t PruneAfter) override { + maybePruneImpl(Path, PruneInterval, PruneAfter); + } + InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; } const InMemoryModuleCache &getInMemoryModuleCache() const override { return InMemory; diff --git a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp index 80db2d47d940e..d1e543b438225 100644 --- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp +++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp @@ -100,6 +100,13 @@ class InProcessModuleCache : public ModuleCache { Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now())); } + void maybePrune(StringRef Path, time_t PruneInterval, + time_t PruneAfter) override { + // FIXME: This only needs to be ran once per build, not in every + // compilation. Call it once per service. + maybePruneImpl(Path, PruneInterval, PruneAfter); + } + InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; } const InMemoryModuleCache &getInMemoryModuleCache() const override { return InMemory; From 0d37b66b17a13e5270f72d00f8c002f21ee32535 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 1 Oct 2025 14:34:02 -0700 Subject: [PATCH 35/41] [clang] Invert condition refactored in #160935 (#161583) The PR #160935 incorrectly replaced `llvm::sys::fs::getUniqueID()` with `llvm::vfs::FileSystem::exists()` in a condition. That's incorrect, since the first function returns `std::error_code` that evaluates to `true` when there is an error (file doesn't exist), while the new code does the opposite. This PR fixes that issue by inverting the conditional. Co-authored-by: ronlieb --- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 2 +- clang/test/OpenMP/amdgcn_save_temps.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 clang/test/OpenMP/amdgcn_save_temps.c diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index cb73cb49d1e26..df9201f26aa18 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1539,7 +1539,7 @@ static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc( SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(BeginLoc); - if (CGM.getFileSystem()->exists(PLoc.getFilename())) + if (!CGM.getFileSystem()->exists(PLoc.getFilename())) PLoc = SM.getPresumedLoc(BeginLoc, /*UseLineDirectives=*/false); return std::pair(PLoc.getFilename(), PLoc.getLine()); diff --git a/clang/test/OpenMP/amdgcn_save_temps.c b/clang/test/OpenMP/amdgcn_save_temps.c new file mode 100644 index 0000000000000..d838bb1166b6b --- /dev/null +++ b/clang/test/OpenMP/amdgcn_save_temps.c @@ -0,0 +1,23 @@ + +// REQUIRES: amdgpu-registered-target + +// RUN: %clang_cc1 -E -fopenmp -x c -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -save-temps=cwd %s -o %t-openmp-amdgcn-amd-amdhsa-gfx90a.i +// RUN: %clang_cc1 -fopenmp -x c -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -save-temps=cwd -emit-llvm-bc %s -o %t-x86_64-unknown-unknown.bc +// RUN: %clang_cc1 -fopenmp -x c -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -save-temps=cwd -emit-llvm -fopenmp-is-target-device -x cpp-output %t-openmp-amdgcn-amd-amdhsa-gfx90a.i -fopenmp-host-ir-file-path %t-x86_64-unknown-unknown.bc -o - | FileCheck %s +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +#define N 1000 + +int test_amdgcn_save_temps() { + int arr[N]; +#pragma omp target + for (int i = 0; i < N; i++) { + arr[i] = 1; + } + return arr[0]; +} +#endif + +// CHECK: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_test_amdgcn_save_temps From b76ea708993345e2186181d55ceb27e979333085 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 1 Oct 2025 14:35:17 -0700 Subject: [PATCH 36/41] [llvm][support] Move `make_absolute` from `sys::fs` to `sys::path` (#161459) The `llvm::sys::fs::make_absolute(const Twine &, SmallVectorImpl &)` functions doesn't perform any FS access - it only modifies the second parameter via path/string operations. This function should live in the `llvm::sys::path` namespace for consistency and for making it easier to spot function calls that perform IO. --- .../lib/Tooling/ApplyReplacements.cpp | 2 +- clang-tools-extra/clang-move/Move.cpp | 2 +- clang-tools-extra/clangd/ConfigCompile.cpp | 2 +- .../clangd/SystemIncludeExtractor.cpp | 2 +- .../clangd/index/SymbolCollector.cpp | 2 +- clang-tools-extra/clangd/tool/ClangdMain.cpp | 2 +- .../include-cleaner/tool/IncludeCleaner.cpp | 2 +- clang/lib/Frontend/CompileJobCache.cpp | 2 +- clang/lib/Lex/HeaderSearch.cpp | 4 +- .../DependencyScanningWorker.cpp | 4 +- .../Frontend/CompilerInstanceTest.cpp | 2 +- llvm/include/llvm/Support/FileSystem.h | 12 --- llvm/include/llvm/Support/Path.h | 12 +++ llvm/lib/Support/Path.cpp | 100 +++++++++--------- llvm/lib/Support/VirtualFileSystem.cpp | 4 +- llvm/tools/llvm-config/llvm-config.cpp | 6 +- llvm/tools/llvm-dwp/llvm-dwp.cpp | 2 +- llvm/tools/llvm-opt-report/OptReport.cpp | 2 +- llvm/unittests/Support/Path.cpp | 4 +- 19 files changed, 84 insertions(+), 84 deletions(-) diff --git a/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp b/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp index b895075e4f31c..0ac8f712e112f 100644 --- a/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp +++ b/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp @@ -142,7 +142,7 @@ groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs, // build directories, make them absolute immediately. SmallString<128> Path = R.getFilePath(); if (BuildDir) - llvm::sys::fs::make_absolute(*BuildDir, Path); + llvm::sys::path::make_absolute(*BuildDir, Path); else SM.getFileManager().makeAbsolutePath(Path); diff --git a/clang-tools-extra/clang-move/Move.cpp b/clang-tools-extra/clang-move/Move.cpp index 17f597170f9f6..519d359991cdb 100644 --- a/clang-tools-extra/clang-move/Move.cpp +++ b/clang-tools-extra/clang-move/Move.cpp @@ -75,7 +75,7 @@ std::string MakeAbsolutePath(StringRef CurrentDir, StringRef Path) { return ""; llvm::SmallString<128> InitialDirectory(CurrentDir); llvm::SmallString<128> AbsolutePath(Path); - llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath); + llvm::sys::path::make_absolute(InitialDirectory, AbsolutePath); return CleanPath(std::move(AbsolutePath)); } diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 35d35f747a868..6a5206df9a261 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -131,7 +131,7 @@ struct FragmentCompiler { return std::nullopt; } llvm::SmallString<256> AbsPath = llvm::StringRef(*Path); - llvm::sys::fs::make_absolute(FragmentDirectory, AbsPath); + llvm::sys::path::make_absolute(FragmentDirectory, AbsPath); llvm::sys::path::native(AbsPath, Style); return AbsPath.str().str(); } diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp index 0b067e8b0b2b2..b4f0c4f765c2f 100644 --- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp +++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp @@ -106,7 +106,7 @@ struct DriverArgs { // relative or absolute). if (llvm::any_of(Driver, [](char C) { return llvm::sys::path::is_separator(C); })) { - llvm::sys::fs::make_absolute(Cmd.Directory, Driver); + llvm::sys::path::make_absolute(Cmd.Directory, Driver); } this->Driver = Driver.str().str(); for (size_t I = 0, E = Cmd.CommandLine.size(); I < E; ++I) { diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 6bdb1080fb294..39c479b5f4d5b 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -325,7 +325,7 @@ class SymbolCollector::HeaderFileURICache { if (R.second) { llvm::SmallString<256> AbsPath = Path; if (!llvm::sys::path::is_absolute(AbsPath) && !FallbackDir.empty()) - llvm::sys::fs::make_absolute(FallbackDir, AbsPath); + llvm::sys::path::make_absolute(FallbackDir, AbsPath); assert(llvm::sys::path::is_absolute(AbsPath) && "If the VFS can't make paths absolute, a FallbackDir must be " "provided"); diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 3be88bd04b6d5..91b2422d412c8 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -577,7 +577,7 @@ class TestScheme : public URIScheme { Body = Body.ltrim('/'); llvm::SmallString<16> Path(Body); path::native(Path); - fs::make_absolute(TestScheme::TestDir, Path); + path::make_absolute(TestScheme::TestDir, Path); return std::string(Path); } diff --git a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp index 372ab5fa2706e..fefbfc3a9614d 100644 --- a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp +++ b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp @@ -344,7 +344,7 @@ mapInputsToAbsPaths(clang::tooling::CompilationDatabase &CDB, } for (const auto &Cmd : Cmds) { llvm::SmallString<256> CDBPath(Cmd.Filename); - llvm::sys::fs::make_absolute(Cmd.Directory, CDBPath); + llvm::sys::path::make_absolute(Cmd.Directory, CDBPath); CDBToAbsPaths[std::string(CDBPath)] = std::string(AbsPath); } } diff --git a/clang/lib/Frontend/CompileJobCache.cpp b/clang/lib/Frontend/CompileJobCache.cpp index 81597274ca5b8..c210d075d26b1 100644 --- a/clang/lib/Frontend/CompileJobCache.cpp +++ b/clang/lib/Frontend/CompileJobCache.cpp @@ -271,7 +271,7 @@ static std::string fixupRelativePath(const std::string &Path, FileManager &FM, // Apply "normal" working directory. if (!WorkingDir.empty()) { SmallString<128> Tmp(Path); - llvm::sys::fs::make_absolute(WorkingDir, Tmp); + llvm::sys::path::make_absolute(WorkingDir, Tmp); return std::string(Tmp); } return Path; diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 39b8fe3e0bd8d..a703fbd00488c 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1989,7 +1989,7 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( llvm::SmallString<32> FilePath = File; if (!WorkingDir.empty() && !path::is_absolute(FilePath)) - fs::make_absolute(WorkingDir, FilePath); + path::make_absolute(WorkingDir, FilePath); // remove_dots switches to backslashes on windows as a side-effect! // We always want to suggest forward slashes for includes. // (not remove_dots(..., posix) as that misparses windows paths). @@ -2003,7 +2003,7 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( // `BestPrefixLength` accordingly. auto CheckDir = [&](llvm::SmallString<32> Dir) -> bool { if (!WorkingDir.empty() && !path::is_absolute(Dir)) - fs::make_absolute(WorkingDir, Dir); + path::make_absolute(WorkingDir, Dir); path::remove_dots(Dir, /*remove_dot_dot=*/true); for (auto NI = path::begin(File), NE = path::end(File), DI = path::begin(Dir), DE = path::end(Dir); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 7c74b9c7decfd..1cafe7d97b5c4 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -61,7 +61,7 @@ class DependencyConsumerForwarder : public DependencyFileGenerator { for (const auto &File : getDependencies()) { CanonPath = File; llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true); - llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath); + llvm::sys::path::make_absolute(WorkingDirectory, CanonPath); C.handleFileDependency(CanonPath); } if (EmitDependencyFile) @@ -1148,7 +1148,7 @@ void DependencyScanningWorker::computeDependenciesFromCompilerInvocation( // FIXME: On Windows, WorkingDirectory is insufficient for making an // absolute path if OutputFile has a root name. llvm::SmallString<128> Path = StringRef(DepFile); - llvm::sys::fs::make_absolute(WorkingDirectory, Path); + llvm::sys::path::make_absolute(WorkingDirectory, Path); DepFile = Path.str().str(); } diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index 47feb366af896..e0f228668b884 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -33,7 +33,7 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) { SmallString<256> CurrentPath; sys::fs::current_path(CurrentPath); - sys::fs::make_absolute(CurrentPath, FileName); + sys::path::make_absolute(CurrentPath, FileName); // Mount the VFS file itself on the path 'virtual.file'. Makes this test // a bit shorter than creating a new dummy file just for this purpose. diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h index 3228dcec13a76..a8cea9d787510 100644 --- a/llvm/include/llvm/Support/FileSystem.h +++ b/llvm/include/llvm/Support/FileSystem.h @@ -266,18 +266,6 @@ class file_status : public basic_file_status { /// @name Physical Operators /// @{ -/// Make \a path an absolute path. -/// -/// Makes \a path absolute using the \a current_directory if it is not already. -/// An empty \a path will result in the \a current_directory. -/// -/// /absolute/path => /absolute/path -/// relative/../path => /relative/../path -/// -/// @param path A path that is modified to be an absolute path. -LLVM_ABI void make_absolute(const Twine ¤t_directory, - SmallVectorImpl &path); - /// Make \a path an absolute path. /// /// Makes \a path absolute using the current directory if it is not already. An diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h index 0cb517146c04b..a8e0f338ec203 100644 --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -566,6 +566,18 @@ LLVM_ABI bool is_absolute_gnu(const Twine &path, Style style = Style::native); /// @result True if the path is relative, false if it is not. LLVM_ABI bool is_relative(const Twine &path, Style style = Style::native); +/// Make \a path an absolute path. +/// +/// Makes \a path absolute using the \a current_directory if it is not already. +/// An empty \a path will result in the \a current_directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => /relative/../path +/// +/// @param path A path that is modified to be an absolute path. +LLVM_ABI void make_absolute(const Twine ¤t_directory, + SmallVectorImpl &path); + } // end namespace path } // end namespace sys } // end namespace llvm diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp index 761d29e960887..3e066665f4155 100644 --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -700,6 +700,55 @@ bool is_relative(const Twine &path, Style style) { return !is_absolute(path, style); } +void make_absolute(const Twine ¤t_directory, + SmallVectorImpl &path) { + StringRef p(path.data(), path.size()); + + bool rootDirectory = has_root_directory(p); + bool rootName = has_root_name(p); + + // Already absolute. + if ((rootName || is_style_posix(Style::native)) && rootDirectory) + return; + + // All the following conditions will need the current directory. + SmallString<128> current_dir; + current_directory.toVector(current_dir); + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + append(current_dir, p); + // Set path to the result. + path.swap(current_dir); + return; + } + + if (!rootName && rootDirectory) { + StringRef cdrn = root_name(current_dir); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + append(curDirRootName, p); + // Set path to the result. + path.swap(curDirRootName); + return; + } + + if (rootName && !rootDirectory) { + StringRef pRootName = root_name(p); + StringRef bRootDirectory = root_directory(current_dir); + StringRef bRelativePath = relative_path(current_dir); + StringRef pRelativePath = relative_path(p); + + SmallString<128> res; + append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); + path.swap(res); + return; + } + + llvm_unreachable("All rootName and rootDirectory combinations should have " + "occurred above!"); +} + StringRef remove_leading_dotslash(StringRef Path, Style style) { // Remove leading "./" (or ".//" or "././" etc.) while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) { @@ -903,55 +952,6 @@ getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix, return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); } -void make_absolute(const Twine ¤t_directory, - SmallVectorImpl &path) { - StringRef p(path.data(), path.size()); - - bool rootDirectory = path::has_root_directory(p); - bool rootName = path::has_root_name(p); - - // Already absolute. - if ((rootName || is_style_posix(Style::native)) && rootDirectory) - return; - - // All of the following conditions will need the current directory. - SmallString<128> current_dir; - current_directory.toVector(current_dir); - - // Relative path. Prepend the current directory. - if (!rootName && !rootDirectory) { - // Append path to the current directory. - path::append(current_dir, p); - // Set path to the result. - path.swap(current_dir); - return; - } - - if (!rootName && rootDirectory) { - StringRef cdrn = path::root_name(current_dir); - SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); - path::append(curDirRootName, p); - // Set path to the result. - path.swap(curDirRootName); - return; - } - - if (rootName && !rootDirectory) { - StringRef pRootName = path::root_name(p); - StringRef bRootDirectory = path::root_directory(current_dir); - StringRef bRelativePath = path::relative_path(current_dir); - StringRef pRelativePath = path::relative_path(p); - - SmallString<128> res; - path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); - path.swap(res); - return; - } - - llvm_unreachable("All rootName and rootDirectory combinations should have " - "occurred above!"); -} - std::error_code make_absolute(SmallVectorImpl &path) { if (path::is_absolute(path)) return {}; @@ -960,7 +960,7 @@ std::error_code make_absolute(SmallVectorImpl &path) { if (std::error_code ec = current_path(current_dir)) return ec; - make_absolute(current_dir, path); + path::make_absolute(current_dir, path); return {}; } diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 8685b096dcd62..52fc7505bffbc 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -153,7 +153,7 @@ std::error_code FileSystem::makeAbsolute(SmallVectorImpl &Path) const { if (!WorkingDir) return WorkingDir.getError(); - llvm::sys::fs::make_absolute(WorkingDir.get(), Path); + sys::path::make_absolute(WorkingDir.get(), Path); return {}; } @@ -320,7 +320,7 @@ class RealFileSystem : public FileSystem { if (!WD || !*WD) return Path; Path.toVector(Storage); - sys::fs::make_absolute(WD->get().Resolved, Storage); + sys::path::make_absolute(WD->get().Resolved, Storage); return Storage; } diff --git a/llvm/tools/llvm-config/llvm-config.cpp b/llvm/tools/llvm-config/llvm-config.cpp index 49df8fdcb7f79..7f8c55ab00989 100644 --- a/llvm/tools/llvm-config/llvm-config.cpp +++ b/llvm/tools/llvm-config/llvm-config.cpp @@ -357,18 +357,18 @@ int main(int argc, char **argv) { ActivePrefix = CurrentExecPrefix; { SmallString<256> Path(LLVM_INSTALL_INCLUDEDIR); - sys::fs::make_absolute(ActivePrefix, Path); + sys::path::make_absolute(ActivePrefix, Path); ActiveIncludeDir = std::string(Path); } { SmallString<256> Path(LLVM_TOOLS_INSTALL_DIR); - sys::fs::make_absolute(ActivePrefix, Path); + sys::path::make_absolute(ActivePrefix, Path); ActiveBinDir = std::string(Path); } ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX; { SmallString<256> Path(LLVM_INSTALL_PACKAGE_DIR); - sys::fs::make_absolute(ActivePrefix, Path); + sys::path::make_absolute(ActivePrefix, Path); ActiveCMakeDir = std::string(Path); } ActiveIncludeOption = "-I" + ActiveIncludeDir; diff --git a/llvm/tools/llvm-dwp/llvm-dwp.cpp b/llvm/tools/llvm-dwp/llvm-dwp.cpp index e34fcadfde5fc..1fb2a654381d1 100644 --- a/llvm/tools/llvm-dwp/llvm-dwp.cpp +++ b/llvm/tools/llvm-dwp/llvm-dwp.cpp @@ -94,7 +94,7 @@ getDWOFilenames(StringRef ExecFilename) { dwarf::toString(Die.find(dwarf::DW_AT_comp_dir), ""); if (!DWOCompDir.empty()) { SmallString<16> DWOPath(DWOName); - sys::fs::make_absolute(DWOCompDir, DWOPath); + sys::path::make_absolute(DWOCompDir, DWOPath); if (!sys::fs::exists(DWOPath) && sys::fs::exists(DWOName)) DWOPaths.push_back(std::move(DWOName)); else diff --git a/llvm/tools/llvm-opt-report/OptReport.cpp b/llvm/tools/llvm-opt-report/OptReport.cpp index 68ed92c8bacea..e4b4fc287b8c1 100644 --- a/llvm/tools/llvm-opt-report/OptReport.cpp +++ b/llvm/tools/llvm-opt-report/OptReport.cpp @@ -274,7 +274,7 @@ static bool writeReport(LocationInfoTy &LocationInfo) { for (auto &FI : LocationInfo) { SmallString<128> FileName(FI.first); if (!InputRelDir.empty()) - sys::fs::make_absolute(InputRelDir, FileName); + sys::path::make_absolute(InputRelDir, FileName); const auto &FileInfo = FI.second; diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp index 355aa6b9ade06..e6d411d1babe4 100644 --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -255,14 +255,14 @@ TEST(Support, Path) { { SmallString<32> Relative("foo.cpp"); - sys::fs::make_absolute("/root", Relative); + path::make_absolute("/root", Relative); Relative[5] = '/'; // Fix up windows paths. ASSERT_EQ("/root/foo.cpp", Relative); } { SmallString<32> Relative("foo.cpp"); - sys::fs::make_absolute("//root", Relative); + path::make_absolute("//root", Relative); Relative[6] = '/'; // Fix up windows paths. ASSERT_EQ("//root/foo.cpp", Relative); } From 93cddf0cf4397ba67c1ce6860b151db6a884eb21 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 2 Oct 2025 12:59:54 -0700 Subject: [PATCH 37/41] [clang] NFCI: Clean up `CompilerInstance::create{File,Source}Manager()` (#160748) The `CompilerInstance::createSourceManager()` function currently accepts the `FileManager` to be used. However, all clients call `CompilerInstance::createFileManager()` prior to creating the `SourceManager`, and it never makes sense to use a `FileManager` in the `SourceManager` that's different from the rest of the compiler. Passing the `FileManager` explicitly is redundant, error-prone, and deviates from the style of other `CompilerInstance` initialization APIs. This PR therefore removes the `FileManager` parameter from `createSourceManager()` and also stops returning the `FileManager` pointer from `createFileManager()`, since that was its primary use. Now, `createSourceManager()` internally calls `getFileManager()` instead. --- .../clang-include-fixer/IncludeFixer.cpp | 2 +- .../include-cleaner/unittests/RecordTest.cpp | 7 ++++--- clang/include/clang/Frontend/CompilerInstance.h | 6 ++---- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 3 +-- clang/lib/Frontend/ChainedIncludesSource.cpp | 2 +- clang/lib/Frontend/CompilerInstance.cpp | 12 +++++++----- clang/lib/Frontend/FrontendAction.cpp | 11 ++++------- clang/lib/Testing/TestAST.cpp | 2 +- .../DependencyScanning/DependencyScanningWorker.cpp | 10 ++++++---- clang/lib/Tooling/Tooling.cpp | 2 +- clang/tools/clang-import-test/clang-import-test.cpp | 2 +- clang/unittests/CodeGen/TestCompiler.h | 2 +- .../Serialization/ForceCheckFileInputTest.cpp | 4 ++-- .../DependencyScanning/DependencyScannerTest.cpp | 2 +- .../ExpressionParser/Clang/ClangExpressionParser.cpp | 2 +- 15 files changed, 34 insertions(+), 35 deletions(-) diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp index a638fb6bbad0e..fa3ec4a975d65 100644 --- a/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp +++ b/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp @@ -96,7 +96,7 @@ bool IncludeFixerActionFactory::runInvocation( // diagnostics here. Compiler.createDiagnostics(new clang::IgnoringDiagConsumer, /*ShouldOwnClient=*/true); - Compiler.createSourceManager(*Files); + Compiler.createSourceManager(); // We abort on fatal errors so don't let a large number of errors become // fatal. A missing #include can cause thousands of errors. diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp index a09ba01fb678c..fc8b23ffcb17c 100644 --- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp @@ -628,11 +628,12 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) { Clang->createVirtualFileSystem(VFS); Clang->createDiagnostics(); - auto *FM = Clang->createFileManager(); + Clang->createFileManager(); + FileManager &FM = Clang->getFileManager(); ASSERT_TRUE(Clang->ExecuteAction(*Inputs.MakeAction())); EXPECT_THAT( - PI.getExporters(llvm::cantFail(FM->getFileRef("foo.h")), *FM), - testing::ElementsAre(llvm::cantFail(FM->getFileRef("exporter.h")))); + PI.getExporters(llvm::cantFail(FM.getFileRef("foo.h")), FM), + testing::ElementsAre(llvm::cantFail(FM.getFileRef("exporter.h")))); } TEST_F(PragmaIncludeTest, OutlivesFMAndSM) { diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 3ad454005770b..91782a2694886 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -755,12 +755,10 @@ class CompilerInstance : public ModuleLoader { const CodeGenOptions *CodeGenOpts = nullptr); /// Create the file manager and replace any existing one with it. - /// - /// \return The new file manager on success, or null on failure. - FileManager *createFileManager(); + void createFileManager(); /// Create the source manager and replace any existing one with it. - void createSourceManager(FileManager &FileMgr); + void createSourceManager(); /// Create the preprocessor, using the invocation, file, and source managers, /// and replace any existing one with it. diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 1087eb3001856..6966d4097d64a 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -444,8 +444,7 @@ bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { return true; if (!CI.hasFileManager()) - if (!CI.createFileManager()) - return false; + CI.createFileManager(); auto Kind = Inputs[0].getKind(); diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp index b6631d3eb9567..990fb3c32a3d0 100644 --- a/clang/lib/Frontend/ChainedIncludesSource.cpp +++ b/clang/lib/Frontend/ChainedIncludesSource.cpp @@ -129,7 +129,7 @@ IntrusiveRefCntPtr clang::createChainedIncludesSource( Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts())); Clang->createFileManager(); - Clang->createSourceManager(Clang->getFileManager()); + Clang->createSourceManager(); Clang->createPreprocessor(TU_Prefix); Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(), &Clang->getPreprocessor()); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 3ea4fc25673ab..593bca1d281e7 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -398,16 +398,18 @@ IntrusiveRefCntPtr CompilerInstance::createDiagnostics( // File Manager -FileManager *CompilerInstance::createFileManager() { +void CompilerInstance::createFileManager() { assert(VFS && "CompilerInstance needs a VFS for creating FileManager"); FileMgr = llvm::makeIntrusiveRefCnt(getFileSystemOpts(), VFS); - return FileMgr.get(); } // Source Manager -void CompilerInstance::createSourceManager(FileManager &FileMgr) { - SourceMgr = new SourceManager(getDiagnostics(), FileMgr); +void CompilerInstance::createSourceManager() { + assert(Diagnostics && "DiagnosticsEngine needed for creating SourceManager"); + assert(FileMgr && "FileManager needed for creating SourceManager"); + SourceMgr = new SourceManager(getDiagnostics(), + getFileManager()); } // Initialize the remapping of files to alternative contents, e.g., @@ -1418,7 +1420,7 @@ std::unique_ptr CompilerInstance::cloneForModuleCompileImpl( if (llvm::is_contained(DiagOpts.SystemHeaderWarningsModules, ModuleName)) Instance.getDiagnostics().setSuppressSystemWarnings(false); - Instance.createSourceManager(Instance.getFileManager()); + Instance.createSourceManager(); SourceManager &SourceMgr = Instance.getSourceManager(); if (ThreadSafeConfig) { diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index e50f1be9ad8aa..ff5a8014b2f74 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -919,7 +919,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // file, otherwise the CompilerInstance will happily destroy them. CI.setVirtualFileSystem(AST->getFileManager().getVirtualFileSystemPtr()); CI.setFileManager(&AST->getFileManager()); - CI.createSourceManager(CI.getFileManager()); + CI.createSourceManager(); CI.getSourceManager().initializeForReplay(AST->getSourceManager()); // Preload all the module files loaded transitively by the AST unit. Also @@ -1011,13 +1011,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Set up the file system, file and source managers, if needed. if (!CI.hasVirtualFileSystem()) CI.createVirtualFileSystem(); - if (!CI.hasFileManager()) { - if (!CI.createFileManager()) { - return false; - } - } + if (!CI.hasFileManager()) + CI.createFileManager(); if (!CI.hasSourceManager()) { - CI.createSourceManager(CI.getFileManager()); + CI.createSourceManager(); if (CI.getDiagnosticOpts().getFormat() == DiagnosticOptions::SARIF) { static_cast(&CI.getDiagnosticClient()) ->setSarifWriter( diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp index 9ad0de95530fb..d3338956f3043 100644 --- a/clang/lib/Testing/TestAST.cpp +++ b/clang/lib/Testing/TestAST.cpp @@ -61,7 +61,7 @@ void createMissingComponents(CompilerInstance &Clang) { if (!Clang.hasFileManager()) Clang.createFileManager(); if (!Clang.hasSourceManager()) - Clang.createSourceManager(Clang.getFileManager()); + Clang.createSourceManager(); if (!Clang.hasTarget()) Clang.createTarget(); if (!Clang.hasPreprocessor()) diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 1cafe7d97b5c4..487d43dc4ec52 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -598,7 +598,7 @@ class DependencyScanningAction { any(Service.getOptimizeArgs() & ScanningOptimizations::VFS); // Create a new FileManager to match the invocation's FileSystemOptions. - auto *FileMgr = ScanInstance.createFileManager(); + ScanInstance.createFileManager(); // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { @@ -606,13 +606,15 @@ class DependencyScanningAction { if (!ScanInstance.getHeaderSearchOpts().ModuleCachePath.empty()) { SmallString<256> ModulesCachePath; normalizeModuleCachePath( - *FileMgr, ScanInstance.getHeaderSearchOpts().ModuleCachePath, + ScanInstance.getFileManager(), + ScanInstance.getHeaderSearchOpts().ModuleCachePath, ModulesCachePath); DepFS->setBypassedPathPrefix(ModulesCachePath); } ScanInstance.setDependencyDirectivesGetter( - std::make_unique(*FileMgr)); + std::make_unique( + ScanInstance.getFileManager())); } // CAS Implementation. @@ -620,7 +622,7 @@ class DependencyScanningAction { ScanInstance.setDependencyDirectivesGetter( std::make_unique(DepCASFS.get())); - ScanInstance.createSourceManager(*FileMgr); + ScanInstance.createSourceManager(); // Create a collection of stable directories derived from the ScanInstance // for determining whether module dependencies would fully resolve from diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 6905c5581cedf..af4a0a25127a0 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -457,7 +457,7 @@ bool FrontendActionFactory::runInvocation( if (!Compiler.hasDiagnostics()) return false; - Compiler.createSourceManager(*Files); + Compiler.createSourceManager(); const bool Success = Compiler.ExecuteAction(*ScopedToolAction); diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp index 5595c3612f517..2ad194f8e170b 100644 --- a/clang/tools/clang-import-test/clang-import-test.cpp +++ b/clang/tools/clang-import-test/clang-import-test.cpp @@ -216,7 +216,7 @@ std::unique_ptr BuildCompilerInstance() { Ins->getTarget().adjust(Ins->getDiagnostics(), Ins->getLangOpts(), /*AuxTarget=*/nullptr); Ins->createFileManager(); - Ins->createSourceManager(Ins->getFileManager()); + Ins->createSourceManager(); Ins->createPreprocessor(TU_Complete); return Ins; diff --git a/clang/unittests/CodeGen/TestCompiler.h b/clang/unittests/CodeGen/TestCompiler.h index 66e45dd259935..1dec035f185c7 100644 --- a/clang/unittests/CodeGen/TestCompiler.h +++ b/clang/unittests/CodeGen/TestCompiler.h @@ -52,7 +52,7 @@ struct TestCompiler { PtrSize = TInfo.getPointerWidth(clang::LangAS::Default) / 8; compiler.createFileManager(); - compiler.createSourceManager(compiler.getFileManager()); + compiler.createSourceManager(); compiler.createPreprocessor(clang::TU_Prefix); compiler.createASTContext(); diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp index fdef7849aa872..70e9fad858767 100644 --- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp +++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp @@ -122,8 +122,8 @@ export int aa = 43; Clang.setDiagnostics(Diags.get()); Clang.createVirtualFileSystem(CIOpts.VFS); - FileManager *FM = Clang.createFileManager(); - Clang.createSourceManager(*FM); + Clang.createFileManager(); + Clang.createSourceManager(); EXPECT_TRUE(Clang.createTarget()); Clang.createPreprocessor(TU_Complete); diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp index ec5e36e07272b..7ea585edca401 100644 --- a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp +++ b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp @@ -69,7 +69,7 @@ class TestDependencyScanningAction : public tooling::ToolAction { if (!Compiler.hasDiagnostics()) return false; - Compiler.createSourceManager(*FileMgr); + Compiler.createSourceManager(); Compiler.addDependencyCollector(std::make_shared( Compiler.getInvocation().getDependencyOutputOpts(), Deps)); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 2bfd15630f60b..2f267fa0b724b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -873,7 +873,7 @@ ClangExpressionParser::ClangExpressionParser( // 6. Set up the source management objects inside the compiler m_compiler->createFileManager(); if (!m_compiler->hasSourceManager()) - m_compiler->createSourceManager(m_compiler->getFileManager()); + m_compiler->createSourceManager(); m_compiler->createPreprocessor(TU_Complete); switch (expr.Language().AsLanguageType()) { From 11d20a0a51d72370d47a9ed8c5a43ecacbffad61 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 6 Oct 2025 10:41:46 -0700 Subject: [PATCH 38/41] [clang] Move `-fprofile-instrument-use-path=` check to driver (#159667) The frontend currently opens the path provided via `-fprofile-instrument-use-path=` to learn the kind of the instrumentation data and set the `CodeGenOptions::ProfileUse` value. This happens during command-line parsing, where we don't have a correctly configured VFS yet, so the behavior is quite different from all other frontend inputs. We need to move this logic out of the frontend command line parsing logic somewhere where we do have the configured VFS. The complication is that the `ProfileUse` flag is being used to set preprocessor macros, and there isn't a great place between command line parsing and preprocessor initialization to perform this logic. This PR solves the issue by deducing the kind of instrumentation data right in the driver and then passing it via a new flag to the frontend. This shouldn't change observable behavior of Clang on the driver level, and only affects the frontend command line interface, which is an implementation detail anyway. --- .../clang/Basic/DiagnosticDriverKinds.td | 3 ++ clang/include/clang/Driver/Options.td | 5 +++ clang/lib/CodeGen/CodeGenModule.cpp | 13 ++++-- clang/lib/Driver/ToolChains/Clang.cpp | 43 ++++++++++++++++--- clang/lib/Frontend/CompilerInvocation.cpp | 39 +++-------------- clang/test/CAS/pgo-profile-with-pch.c | 6 +-- clang/test/CAS/pgo-profile.c | 16 +++---- clang/test/CodeGen/cspgo-instrumentation.c | 6 +-- .../test/CodeGen/cspgo-instrumentation_lto.c | 6 +-- .../CodeGen/cspgo-instrumentation_thinlto.c | 8 ++-- clang/test/CodeGen/opt-record.c | 2 +- clang/test/CodeGen/pgo-instrumentation.c | 4 +- .../thinlto-clang-diagnostic-handler-in-be.c | 2 +- .../CodeGenCXX/fdebug-info-for-profiling.cpp | 2 +- clang/test/CodeGenCXX/profile-remap.cpp | 4 +- clang/test/Driver/Inputs/a.proftext | 2 + clang/test/Driver/cl-options.c | 17 +++++--- clang/test/Driver/clang_f_opts.c | 18 +++++--- clang/test/Driver/fcs-profile-generate.c | 12 ++++-- clang/test/Driver/fsplit-machine-functions.c | 12 ++++-- .../optimization-remark-with-hotness-new-pm.c | 11 ++--- clang/test/Profile/c-captured.c | 2 +- clang/test/Profile/c-counter-overflows.c | 2 +- clang/test/Profile/c-general.c | 8 ++-- clang/test/Profile/c-outdated-data.c | 4 +- clang/test/Profile/c-unprofiled-blocks.c | 2 +- clang/test/Profile/c-unprofiled.c | 2 +- clang/test/Profile/cxx-class.cpp | 2 +- clang/test/Profile/cxx-hash-v2.cpp | 4 +- clang/test/Profile/cxx-lambda.cpp | 2 +- clang/test/Profile/cxx-missing-bodies.cpp | 2 +- .../Profile/cxx-never-executed-branch.cpp | 2 +- clang/test/Profile/cxx-rangefor.cpp | 2 +- clang/test/Profile/cxx-templates.cpp | 2 +- clang/test/Profile/cxx-throws.cpp | 4 +- clang/test/Profile/func-entry.c | 2 +- clang/test/Profile/misexpect-branch-cold.c | 2 +- .../misexpect-branch-nonconst-expected-val.c | 2 +- .../Profile/misexpect-branch-unpredictable.c | 2 +- clang/test/Profile/misexpect-branch.c | 8 ++-- clang/test/Profile/misexpect-switch-default.c | 2 +- .../test/Profile/misexpect-switch-nonconst.c | 2 +- .../misexpect-switch-only-default-case.c | 2 +- clang/test/Profile/misexpect-switch.c | 2 +- clang/test/Profile/objc-general.m | 2 +- .../test/Profile/profile-does-not-exist-ir.c | 10 +++-- clang/test/Profile/profile-does-not-exist.c | 6 ++- clang/test/Profile/profile-summary.c | 2 +- 48 files changed, 179 insertions(+), 136 deletions(-) create mode 100644 clang/test/Driver/Inputs/a.proftext diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index b301736b3dbda..0141205adafd5 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -683,6 +683,9 @@ def warn_drv_fine_grained_bitfield_accesses_ignored : Warning< "option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">, InGroup; +def err_drv_profile_instrument_use_path_with_no_kind : Error< + "option '-fprofile-instrument-use-path=' requires -fprofile-instrument-use=">; + def note_drv_verify_prefix_spelling : Note< "-verify prefixes must start with a letter and contain only alphanumeric" " characters, hyphens, and underscores">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 20cc72ab9c5dd..8962a035a4e2a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -8084,6 +8084,11 @@ def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">, HelpText<"Generate instrumented code to collect execution counts into " " (overridden by LLVM_PROFILE_FILE env var)">, MarshallingInfoString>; +def fprofile_instrument_use_EQ : Joined<["-"], "fprofile-instrument-use=">, + HelpText<"Enable PGO use instrumentation">, Values<"none,clang,llvm,csllvm,sample-coldcov">, + NormalizedValuesScope<"llvm::driver::ProfileInstrKind">, + NormalizedValues<["ProfileNone", "ProfileClangInstr", "ProfileIRInstr", "ProfileCSIRInstr", "ProfileIRSampleColdCov"]>, + MarshallingInfoEnum, "ProfileNone">; def fprofile_instrument_use_path_EQ : Joined<["-"], "fprofile-instrument-use-path=">, HelpText<"Specify the profile path in PGO use compilation">, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 3898d8121b18b..138c007c2834f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -496,10 +496,15 @@ CodeGenModule::CodeGenModule(ASTContext &C, auto ReaderOrErr = llvm::IndexedInstrProfReader::create( CodeGenOpts.ProfileInstrumentUsePath, *FS, CodeGenOpts.ProfileRemappingFile); - // We're checking for profile read errors in CompilerInvocation, so if - // there was an error it should've already been caught. If it hasn't been - // somehow, trip an assertion. - assert(ReaderOrErr); + if (auto E = ReaderOrErr.takeError()) { + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "Error in reading profile %0: %1"); + llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) { + Diags.Report(DiagID) + << CodeGenOpts.ProfileInstrumentUsePath << EI.message(); + }); + return; + } PGOReader = std::move(ReaderOrErr.get()); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 1c2d82ff10c2f..33ebc7cd25f62 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -41,6 +41,7 @@ #include "llvm/Frontend/Debug/Options.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" @@ -502,19 +503,47 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } if (ProfileUseArg) { + SmallString<128> UsePathBuf; + StringRef UsePath; if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) - CmdArgs.push_back(Args.MakeArgString( - Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue())); + UsePath = ProfileUseArg->getValue(); else if ((ProfileUseArg->getOption().matches( options::OPT_fprofile_use_EQ) || ProfileUseArg->getOption().matches( options::OPT_fprofile_instr_use))) { - SmallString<128> Path( - ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); - if (Path.empty() || llvm::sys::fs::is_directory(Path)) - llvm::sys::path::append(Path, "default.profdata"); + UsePathBuf = + ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue(); + if (UsePathBuf.empty() || llvm::sys::fs::is_directory(UsePathBuf)) + llvm::sys::path::append(UsePathBuf, "default.profdata"); + UsePath = UsePathBuf; + } + auto ReaderOrErr = + llvm::IndexedInstrProfReader::create(UsePath, D.getVFS()); + if (auto E = ReaderOrErr.takeError()) { + auto DiagID = D.getDiags().getCustomDiagID( + DiagnosticsEngine::Error, "Error in reading profile %0: %1"); + llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) { + D.Diag(DiagID) << UsePath.str() << EI.message(); + }); + } else { + std::unique_ptr PGOReader = + std::move(ReaderOrErr.get()); + StringRef UseKind; + // Currently memprof profiles are only added at the IR level. Mark the + // profile type as IR in that case as well and the subsequent matching + // needs to detect which is available (might be one or both). + if (PGOReader->isIRLevelProfile() || PGOReader->hasMemoryProfile()) { + if (PGOReader->hasCSIRLevelProfile()) + UseKind = "csllvm"; + else + UseKind = "llvm"; + } else + UseKind = "clang"; + + CmdArgs.push_back( + Args.MakeArgString("-fprofile-instrument-use=" + UseKind)); CmdArgs.push_back( - Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path)); + Args.MakeArgString("-fprofile-instrument-use-path=" + UsePath)); } } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2d1117e42c083..c4c738ef3604c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1621,34 +1621,6 @@ createBaseFS(const FileSystemOptions &FSOpts, const FrontendOptions &FEOpts, return FS; } -// Set the profile kind using fprofile-instrument-use-path. -static void setPGOUseInstrumentor(CodeGenOptions &Opts, - const Twine &ProfileName, - llvm::vfs::FileSystem &FS, - DiagnosticsEngine &Diags) { - auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName, FS); - if (auto E = ReaderOrErr.takeError()) { - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "Error in reading profile %0: %1"); - llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) { - Diags.Report(DiagID) << ProfileName.str() << EI.message(); - }); - return; - } - std::unique_ptr PGOReader = - std::move(ReaderOrErr.get()); - // Currently memprof profiles are only added at the IR level. Mark the profile - // type as IR in that case as well and the subsequent matching needs to detect - // which is available (might be one or both). - if (PGOReader->isIRLevelProfile() || PGOReader->hasMemoryProfile()) { - if (PGOReader->hasCSIRLevelProfile()) - Opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileCSIRInstr); - else - Opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileIRInstr); - } else - Opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileClangInstr); -} - void CompilerInvocation::setDefaultPointerAuthOptions( PointerAuthOptions &Opts, const LangOptions &LangOpts, const llvm::Triple &Triple) { @@ -2214,12 +2186,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, : llvm::codegenoptions::DebugTemplateNamesKind::Mangled); } - if (!Opts.ProfileInstrumentUsePath.empty()) { - auto FS = createBaseFS(FSOpts, FEOpts, CASOpts, Diags, - llvm::vfs::getRealFileSystem(), nullptr); - setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath, *FS, Diags); - } - if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ, OPT_ftime_report_json)) { Opts.TimePasses = true; @@ -5644,6 +5610,11 @@ bool CompilerInvocation::CreateFromArgsImpl( append_range(Res.getCodeGenOpts().CommandLineArgs, CommandLineArgs); } + if (!Res.getCodeGenOpts().ProfileInstrumentUsePath.empty() && + Res.getCodeGenOpts().getProfileUse() == + llvm::driver::ProfileInstrKind::ProfileNone) + Diags.Report(diag::err_drv_profile_instrument_use_path_with_no_kind); + FixupInvocation(Res, Diags, Args, DashX); return Diags.getNumErrors() == NumErrorsBefore; diff --git a/clang/test/CAS/pgo-profile-with-pch.c b/clang/test/CAS/pgo-profile-with-pch.c index 03ed10cc46047..e1d40f29665db 100644 --- a/clang/test/CAS/pgo-profile-with-pch.c +++ b/clang/test/CAS/pgo-profile-with-pch.c @@ -4,7 +4,7 @@ // RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgo.profraw // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t-pch.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-pch -O3 -Rcompile-job-cache \ -// RUN: -x c-header %s -o %t.h.pch -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata +// RUN: -x c-header %s -o %t.h.pch -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata // RUN: %clang @%t-pch.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS // RUN: FileCheck %s -check-prefix=PCHPROF -input-file %t-pch.rsp // PCHPROF-NOT: -fprofile-instrument-use-path @@ -14,14 +14,14 @@ // Use the modified profdata file for the main file along with the PCH. // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata -include-pch %t.h.pch +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -include-pch %t.h.pch // RUN: %clang @%t.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS // RUN: FileCheck %s -check-prefix=TUPROF -input-file %t.rsp // TUPROF: -fprofile-instrument-use-path // Check that the modified profdata is ignored when re-scanning for the PCH. // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t-pch2.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-pch -O3 -Rcompile-job-cache \ -// RUN: -x c-header %s -o %t.h.pch -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata +// RUN: -x c-header %s -o %t.h.pch -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata // RUN: diff -u %t-pch.rsp %t-pch2.rsp // CACHE-MISS: remark: compile job cache miss diff --git a/clang/test/CAS/pgo-profile.c b/clang/test/CAS/pgo-profile.c index cf0f024f2aae0..a474754d69726 100644 --- a/clang/test/CAS/pgo-profile.c +++ b/clang/test/CAS/pgo-profile.c @@ -3,7 +3,7 @@ /// Check use pgo profile. // RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgo.profraw // RUN: %clang -cc1depscan -fdepscan=inline -o %t.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata /// Remove profile data to make sure the cc1 command is not reading from file system. // RUN: rm %t.profdata @@ -13,7 +13,7 @@ /// Check include tree. // RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgo.profraw // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t1.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata // RUN: rm %t.profdata // RUN: %clang @%t1.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS // RUN: %clang @%t1.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-HIT @@ -21,12 +21,12 @@ /// Check change profile data will cause cache miss. // RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgo2.profraw // RUN: %clang -cc1depscan -fdepscan=inline -o %t2.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata // RUN: not diff %t.rsp %t2.rsp // RUN: %clang @%t2.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t3.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata // RUN: not diff %t1.rsp %t3.rsp // RUN: %clang @%t3.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS @@ -38,9 +38,9 @@ // RUN: cp %t.profdata %t.dir/a/a.profdata // RUN: cp %t.profdata %t.dir/b/a.profdata // RUN: %clang -cc1depscan -fdepscan=inline -o %t4.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache -fdepscan-prefix-map %t.dir/a /^testdir \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.dir/a/a.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.dir/a/a.profdata // RUN: %clang -cc1depscan -fdepscan=inline -o %t5.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache -fdepscan-prefix-map %t.dir/b /^testdir \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.dir/b/a.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.dir/b/a.profdata // RUN: cat %t4.rsp | FileCheck %s --check-prefix=REMAP // RUN: %clang @%t4.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS // RUN: %clang @%t5.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-HIT @@ -55,9 +55,9 @@ // RUN: diff -u %t.dir/cache-key1 %t.dir/cache-key2 // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t4.inc.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache -fdepscan-prefix-map %t.dir/a /^testdir \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.dir/a/a.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.dir/a/a.profdata // RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t5.inc.rsp -cc1-args -cc1 -triple x86_64-apple-macosx12.0.0 -emit-obj -O3 -Rcompile-job-cache -fdepscan-prefix-map %t.dir/b /^testdir \ -// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use-path=%t.dir/b/a.profdata +// RUN: -x c %s -o %t.o -fcas-path %t.dir/cas -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.dir/b/a.profdata // RUN: cat %t4.inc.rsp | FileCheck %s --check-prefix=REMAP // RUN: %clang @%t4.inc.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-MISS // RUN: %clang @%t5.inc.rsp 2>&1 | FileCheck %s --check-prefix=CACHE-HIT diff --git a/clang/test/CodeGen/cspgo-instrumentation.c b/clang/test/CodeGen/cspgo-instrumentation.c index 3f90bb4396d70..f42d68aba0eaa 100644 --- a/clang/test/CodeGen/cspgo-instrumentation.c +++ b/clang/test/CodeGen/cspgo-instrumentation.c @@ -9,19 +9,19 @@ // RUN: llvm-profdata merge -o %t/noncs.profdata %S/Inputs/pgotestir.proftext // // Ensure Pass PGOInstrumentationUsePass and PGOInstrumentationGenPass are invoked. -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/noncs.profdata -fprofile-instrument=csllvm -fprofile-instrument-path=default.profraw %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN2 +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t/noncs.profdata -fprofile-instrument=csllvm -fprofile-instrument-path=default.profraw %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN2 // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN2: Running pass: PGOInstrumentationUse // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN2: Running pass: PGOInstrumentationGenCreateVar on // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN2: Running pass: PGOInstrumentationGen on // Ensure Pass PGOInstrumentationUsePass is invoked only once. -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/noncs.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t/noncs.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE // CHECK-PGOUSEPASS-INVOKED-USE: Running pass: PGOInstrumentationUse // CHECK-PGOUSEPASS-INVOKED-USE-NOT: Running pass: PGOInstrumentationGenCreateVar // CHECK-PGOUSEPASS-INVOKED-USE-NOT: Running pass: PGOInstrumentationUse // // Ensure Pass PGOInstrumentationUsePass is invoked twice. // RUN: llvm-profdata merge -o %t/cs.profdata %S/Inputs/pgotestir_cs.proftext -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/cs.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE2 +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=csllvm -fprofile-instrument-use-path=%t/cs.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE2 // CHECK-PGOUSEPASS-INVOKED-USE2: Running pass: PGOInstrumentationUse // CHECK-PGOUSEPASS-INVOKED-USE2: Running pass: PGOInstrumentationUse diff --git a/clang/test/CodeGen/cspgo-instrumentation_lto.c b/clang/test/CodeGen/cspgo-instrumentation_lto.c index c4296842ae50e..5d541c6688a1f 100644 --- a/clang/test/CodeGen/cspgo-instrumentation_lto.c +++ b/clang/test/CodeGen/cspgo-instrumentation_lto.c @@ -4,7 +4,7 @@ // RUN: llvm-profdata merge -o %t/noncs.profdata %S/Inputs/pgotestir.proftext // // Ensure Pass PGOInstrumentationGenPass is not invoked in PreLink. -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/noncs.profdata -fprofile-instrument=csllvm %s -flto -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t/noncs.profdata -fprofile-instrument=csllvm %s -flto -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE: Running pass: PGOInstrumentationUse // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE: Running pass: PGOInstrumentationGenCreateVar // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE-NOT: Running pass: PGOInstrumentationGen on @@ -18,12 +18,12 @@ // RUN: llvm-profdata merge -o %t/cs.profdata %S/Inputs/pgotestir_cs.proftext // // Ensure Pass PGOInstrumentationUsePass is invoked Once in PreLink. -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/cs.profdata %s -flto -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=csllvm -fprofile-instrument-use-path=%t/cs.profdata %s -flto -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE: Running pass: PGOInstrumentationUse // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE-NOT: Running pass: PGOInstrumentationGenCreateVar // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE-NOT: Running pass: PGOInstrumentationUse // // Ensure Pass PGOInstrumentationUSEPass is invoked in PostLink. -// RUN: %clang_cc1 -O2 -x ir %t/foo_fe_pm.bc -fdebug-pass-manager -fprofile-instrument-use-path=%t/cs.profdata -flto -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST +// RUN: %clang_cc1 -O2 -x ir %t/foo_fe_pm.bc -fdebug-pass-manager -fprofile-instrument-use=csllvm -fprofile-instrument-use-path=%t/cs.profdata -flto -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST: Running pass: PGOInstrumentationUse // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST-NOT: Running pass: PGOInstrumentationUse diff --git a/clang/test/CodeGen/cspgo-instrumentation_thinlto.c b/clang/test/CodeGen/cspgo-instrumentation_thinlto.c index f79433827ce17..0627f64a69728 100644 --- a/clang/test/CodeGen/cspgo-instrumentation_thinlto.c +++ b/clang/test/CodeGen/cspgo-instrumentation_thinlto.c @@ -4,7 +4,7 @@ // RUN: llvm-profdata merge -o %t/noncs.profdata %S/Inputs/pgotestir.proftext // // Ensure Pass PGOInstrumentationGenPass is not invoked in PreLink. -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/noncs.profdata -fprofile-instrument=csllvm %s -fprofile-instrument-path=default.profraw -flto=thin -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t/noncs.profdata -fprofile-instrument=csllvm %s -fprofile-instrument-path=default.profraw -flto=thin -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE: Running pass: PGOInstrumentationUse // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE: Running pass: PGOInstrumentationGenCreateVar // CHECK-CSPGOGENPASS-INVOKED-INSTR-GEN-PRE-NOT: Running pass: PGOInstrumentationGen on @@ -19,16 +19,16 @@ // RUN: llvm-profdata merge -o %t/cs.profdata %S/Inputs/pgotestir_cs.proftext // // Ensure Pass PGOInstrumentationUsePass is invoked Once in PreLink. -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t/cs.profdata %s -flto=thin -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=csllvm -fprofile-instrument-use-path=%t/cs.profdata %s -flto=thin -fdebug-pass-manager -emit-llvm-bc -o %t/foo_fe_pm.bc 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE: Running pass: PGOInstrumentationUse // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-PRE-NOT: Running pass: PGOInstrumentationUse // // RUN: llvm-lto -thinlto -o %t/foo_pm %t/foo_fe_pm.bc // Ensure Pass PGOInstrumentationUSEPass is invoked in PostLink. -// RUN: %clang_cc1 -O2 -x ir %t/foo_fe_pm.bc -fthinlto-index=%t/foo_pm.thinlto.bc -fdebug-pass-manager -fprofile-instrument-use-path=%t/cs.profdata -flto=thin -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST +// RUN: %clang_cc1 -O2 -x ir %t/foo_fe_pm.bc -fthinlto-index=%t/foo_pm.thinlto.bc -fdebug-pass-manager -fprofile-instrument-use=csllvm -fprofile-instrument-use-path=%t/cs.profdata -flto=thin -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST: Running pass: PGOInstrumentationUse // CHECK-CSPGOUSEPASS-INVOKED-INSTR-USE-POST-NOT: Running pass: PGOInstrumentationUse // // Finally, test if a non-cs profile is passed to PostLink passes, PGO UsePass is not invoked. -// RUN: %clang_cc1 -O2 -x ir %t/foo_fe_pm.bc -fthinlto-index=%t/foo_pm.thinlto.bc -fdebug-pass-manager -fprofile-instrument-use-path=%t/noncs.profdata -flto=thin -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-INSTR-USE-POST +// RUN: %clang_cc1 -O2 -x ir %t/foo_fe_pm.bc -fthinlto-index=%t/foo_pm.thinlto.bc -fdebug-pass-manager -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t/noncs.profdata -flto=thin -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-INSTR-USE-POST // CHECK-PGOUSEPASS-INVOKED-INSTR-USE-POST-NOT: Running pass: PGOInstrumentationUse diff --git a/clang/test/CodeGen/opt-record.c b/clang/test/CodeGen/opt-record.c index 391c14b7bbcc2..f54a6225760aa 100644 --- a/clang/test/CodeGen/opt-record.c +++ b/clang/test/CodeGen/opt-record.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux-gnu -target-cpu x86-64 %s -o %t -opt-record-file %t.yaml -emit-obj // RUN: cat %t.yaml | FileCheck %s // RUN: llvm-profdata merge %S/Inputs/opt-record.proftext -o %t.profdata -// RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux-gnu -target-cpu x86-64 -fprofile-instrument-use-path=%t.profdata %s -o %t -opt-record-file %t.yaml -emit-obj +// RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux-gnu -target-cpu x86-64 -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata %s -o %t -opt-record-file %t.yaml -emit-obj // RUN: cat %t.yaml | FileCheck -check-prefix=CHECK -check-prefix=CHECK-PGO %s // RUN: %clang_cc1 -O3 -triple x86_64-unknown-linux-gnu -target-cpu x86-64 %s -o %t -opt-record-file %t.yaml -opt-record-passes inline -emit-obj // RUN: cat %t.yaml | FileCheck -check-prefix=CHECK-PASSES %s diff --git a/clang/test/CodeGen/pgo-instrumentation.c b/clang/test/CodeGen/pgo-instrumentation.c index c01658065497e..7c878250ae33e 100644 --- a/clang/test/CodeGen/pgo-instrumentation.c +++ b/clang/test/CodeGen/pgo-instrumentation.c @@ -15,10 +15,10 @@ // Ensure Pass PGOInstrumentationUsePass is invoked. // RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgotestir.profraw -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-INSTR-USE +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-INSTR-USE // CHECK-PGOUSEPASS-INVOKED-INSTR-USE: Running pass: PGOInstrumentationUse on // // Ensure Pass PGOInstrumentationUsePass is not invoked. // RUN: llvm-profdata merge -o %t.profdata %S/Inputs/pgotestclang.profraw -// RUN: %clang_cc1 -O2 -fprofile-instrument-use-path=%t.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE-CLANG +// RUN: %clang_cc1 -O2 -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata %s -fdebug-pass-manager -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=CHECK-PGOUSEPASS-INVOKED-USE-CLANG // CHECK-PGOUSEPASS-INVOKED-USE-CLANG-NOT: Running pass: PGOInstrumentationUse on diff --git a/clang/test/CodeGen/thinlto-clang-diagnostic-handler-in-be.c b/clang/test/CodeGen/thinlto-clang-diagnostic-handler-in-be.c index efbcc851ad770..a12574d28c731 100644 --- a/clang/test/CodeGen/thinlto-clang-diagnostic-handler-in-be.c +++ b/clang/test/CodeGen/thinlto-clang-diagnostic-handler-in-be.c @@ -7,7 +7,7 @@ // RUN: llvm-lto -thinlto -o %t %t1.bo // RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -x ir %t1.bo -fthinlto-index=%t.thinlto.bc -emit-obj -Rpass-analysis=info 2>&1 | FileCheck %s -check-prefix=CHECK-REMARK // RUN: llvm-profdata merge -o %t2.profdata %S/Inputs/thinlto_expect2.proftext -// RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -x ir %t1.bo -fthinlto-index=%t.thinlto.bc -fprofile-instrument-use-path=%t2.profdata -emit-obj 2>&1 | FileCheck %s -allow-empty -check-prefix=CHECK-NOWARNING +// RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -x ir %t1.bo -fthinlto-index=%t.thinlto.bc -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t2.profdata -emit-obj 2>&1 | FileCheck %s -allow-empty -check-prefix=CHECK-NOWARNING int sum; __attribute__((noinline)) void bar(void) { diff --git a/clang/test/CodeGenCXX/fdebug-info-for-profiling.cpp b/clang/test/CodeGenCXX/fdebug-info-for-profiling.cpp index e468a8098d7c8..63de73c90bd2f 100644 --- a/clang/test/CodeGenCXX/fdebug-info-for-profiling.cpp +++ b/clang/test/CodeGenCXX/fdebug-info-for-profiling.cpp @@ -13,7 +13,7 @@ // RUN: echo > %t.proftext // RUN: llvm-profdata merge %t.proftext -o %t.profdata -// RUN: %clang_cc1 -emit-llvm -fdebug-pass-manager -O1 -fprofile-instrument-use-path=%t.profdata -fdebug-info-for-profiling %s -o - 2>&1 | FileCheck %s --check-prefix=DISCR +// RUN: %clang_cc1 -emit-llvm -fdebug-pass-manager -O1 -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -fdebug-info-for-profiling %s -o - 2>&1 | FileCheck %s --check-prefix=DISCR // RUN: %clang_cc1 -emit-llvm -fdebug-pass-manager -O1 -fdebug-info-for-profiling -fpseudo-probe-for-profiling %s -o - 2>&1 | FileCheck %s --check-prefix=PROBE // NODISCR-NOT: Running pass: AddDiscriminatorsPass diff --git a/clang/test/CodeGenCXX/profile-remap.cpp b/clang/test/CodeGenCXX/profile-remap.cpp index b27f67da58ff9..f077f929f406d 100644 --- a/clang/test/CodeGenCXX/profile-remap.cpp +++ b/clang/test/CodeGenCXX/profile-remap.cpp @@ -2,9 +2,9 @@ // // RUN: %clang_cc1 -triple x86_64-linux-gnu -fprofile-sample-use=%S/Inputs/profile-remap.samples -fprofile-remapping-file=%S/Inputs/profile-remap.map -O2 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SAMPLES // RUN: llvm-profdata merge -output %T.profdata %S/Inputs/profile-remap.proftext -// RUN: %clang_cc1 -triple x86_64-linux-gnu -fprofile-instrument-use-path=%T.profdata -fprofile-remapping-file=%S/Inputs/profile-remap.map -O2 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-INSTR +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%T.profdata -fprofile-remapping-file=%S/Inputs/profile-remap.map -O2 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-INSTR // RUN: llvm-profdata merge -output %T.profdata %S/Inputs/profile-remap_entry.proftext -// RUN: %clang_cc1 -triple x86_64-linux-gnu -fprofile-instrument-use-path=%T.profdata -fprofile-remapping-file=%S/Inputs/profile-remap.map -O2 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-INSTR +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%T.profdata -fprofile-remapping-file=%S/Inputs/profile-remap.map -O2 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-INSTR namespace Foo { struct X {}; diff --git a/clang/test/Driver/Inputs/a.proftext b/clang/test/Driver/Inputs/a.proftext new file mode 100644 index 0000000000000..05ab839db07c7 --- /dev/null +++ b/clang/test/Driver/Inputs/a.proftext @@ -0,0 +1,2 @@ +# IR level Instrumentation Flag +:ir diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 57e16e8795a28..22cb04bc95530 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -90,16 +90,21 @@ // RUN: not %clang_cl -### /FAcsu -fprofile-instr-generate -fprofile-instr-use=file -- %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s // CHECK-NO-MIX-GEN-USE: '{{[a-z=-]*}}' not allowed with '{{[a-z=-]*}}' +// RUN: rm -rf %t && mkdir %t +// RUN: llvm-profdata merge -o %t/somefile.prof %S/Inputs/a.proftext +// RUN: llvm-profdata merge -o %t/default.profdata %S/Inputs/a.proftext +// RUN: cd %t + // RUN: %clang_cl -### /FA -fprofile-instr-use -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s // RUN: %clang_cl -### /FA -fprofile-use -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s -// RUN: %clang_cl -### /FA -fprofile-instr-use=/tmp/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s -// RUN: %clang_cl -### /FA -fprofile-use=/tmp/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// RUN: %clang_cl -### /FA -fprofile-instr-use=%t/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// RUN: %clang_cl -### /FA -fprofile-use=%t/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s // RUN: %clang_cl -### /FAcsu -fprofile-instr-use -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s // RUN: %clang_cl -### /FAcsu -fprofile-use -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s -// RUN: %clang_cl -### /FAcsu -fprofile-instr-use=/tmp/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s -// RUN: %clang_cl -### /FAcsu -fprofile-use=/tmp/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s -// CHECK-PROFILE-USE: "-fprofile-instrument-use-path=default.profdata" -// CHECK-PROFILE-USE-FILE: "-fprofile-instrument-use-path=/tmp/somefile.prof" +// RUN: %clang_cl -### /FAcsu -fprofile-instr-use=%t/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// RUN: %clang_cl -### /FAcsu -fprofile-use=%t/somefile.prof -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// CHECK-PROFILE-USE: "-fprofile-instrument-use-path={{.*}}default.profdata" +// CHECK-PROFILE-USE-FILE: "-fprofile-instrument-use-path={{.*}}somefile.prof" // RUN: %clang_cl /GA -### -- %s 2>&1 | FileCheck -check-prefix=GA %s // GA: -ftls-model=local-exec diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index ee7ded265769b..a68e60f2a9738 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -122,16 +122,22 @@ // CHECK-DISABLE-COVERAGE-NOT: "-fcoverage-mapping" // CHECK-PROFILE-REMAP: "-fprofile-remapping-file=foo/bar.txt" +// RUN: rm -rf %t && mkdir %t +// RUN: llvm-profdata merge -o %t/somefile.prof %S/Inputs/a.proftext +// RUN: llvm-profdata merge -o %t/default.profdata %S/Inputs/a.proftext +// RUN: cd %t + // RUN: %clang -### -S -fprofile-use %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s // RUN: %clang -### -S -fprofile-instr-use %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE %s -// RUN: mkdir -p %t.d/some/dir -// RUN: %clang -### -S -fprofile-use=%t.d/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-DIR %s -// RUN: %clang -### -S -fprofile-instr-use=/tmp/somefile.prof %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s +// RUN: mkdir -p %t/some/dir +// RUN: cp %t/default.profdata %t/some/dir +// RUN: %clang -### -S -fprofile-use=%t/some/dir %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-DIR %s +// RUN: %clang -### -S -fprofile-instr-use=%t/somefile.prof %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-USE-FILE %s // CHECK-PROFILE-USE: "-fprofile-instrument-use-path=default.profdata" -// CHECK-PROFILE-USE-DIR: "-fprofile-instrument-use-path={{.*}}.d/some/dir{{/|\\\\}}default.profdata" -// CHECK-PROFILE-USE-FILE: "-fprofile-instrument-use-path=/tmp/somefile.prof" +// CHECK-PROFILE-USE-DIR: "-fprofile-instrument-use-path={{.*}}some/dir{{/|\\\\}}default.profdata" +// CHECK-PROFILE-USE-FILE: "-fprofile-instrument-use-path={{.*}}somefile.prof" -// RUN: %clang -### -S -fprofile-instr-use=%t.profdata -fdiagnostics-misexpect-tolerance=10 -Wmisexpect %s 2>&1 | FileCheck %s --check-prefix=CHECK-MISEXPECT-TOLLERANCE +// RUN: %clang -### -S -fprofile-instr-use=%t/somefile.prof -fdiagnostics-misexpect-tolerance=10 -Wmisexpect %s 2>&1 | FileCheck %s --check-prefix=CHECK-MISEXPECT-TOLLERANCE // CHECK-MISEXPECT-TOLLERANCE: "-fdiagnostics-misexpect-tolerance=10" // CHECK-MISEXPECT-TOLLERANCE-NOT: argument unused diff --git a/clang/test/Driver/fcs-profile-generate.c b/clang/test/Driver/fcs-profile-generate.c index f69fa44be873e..ecb5aad58fd46 100644 --- a/clang/test/Driver/fcs-profile-generate.c +++ b/clang/test/Driver/fcs-profile-generate.c @@ -1,10 +1,14 @@ -// RUN: %clang -### -c -fprofile-use=a.profdata -fcs-profile-generate %s 2>&1 | FileCheck %s +// RUN: rm -rf %t && mkdir %t +// RUN: llvm-profdata merge -o %t/a.profdata %S/Inputs/a.proftext + +// RUN: %clang -### -c -fprofile-use=%t/a.profdata -fcs-profile-generate %s 2>&1 | FileCheck %s // CHECK: "-fprofile-instrument=csllvm" // CHECK-NOT: "-fprofile-instrument-path= -// CHECK-SAME: "-fprofile-instrument-use-path=a.profdata" +// CHECK-SAME: "-fprofile-instrument-use=llvm" +// CHECK-SAME: "-fprofile-instrument-use-path={{.*}}a.profdata" -// RUN: %clang -### -c -fprofile-use=a.profdata -fcs-profile-generate=dir %s 2>&1 | FileCheck %s --check-prefix=CHECK1 -// CHECK1: "-fprofile-instrument=csllvm"{{.*}} "-fprofile-instrument-path=dir{{/|\\\\}}default_%m.profraw" "-fprofile-instrument-use-path=a.profdata" +// RUN: %clang -### -c -fprofile-use=%t/a.profdata -fcs-profile-generate=dir %s 2>&1 | FileCheck %s --check-prefix=CHECK1 +// CHECK1: "-fprofile-instrument=csllvm"{{.*}} "-fprofile-instrument-path=dir{{/|\\\\}}default_%m.profraw" "-fprofile-instrument-use=llvm" "-fprofile-instrument-use-path={{.*}}a.profdata" /// Degradation case. This usage does not make much sense. // RUN: %clang -### -c -fcs-profile-generate %s 2>&1 | FileCheck %s --check-prefix=NOUSE diff --git a/clang/test/Driver/fsplit-machine-functions.c b/clang/test/Driver/fsplit-machine-functions.c index 02bab476e831d..153aafba8fbd0 100644 --- a/clang/test/Driver/fsplit-machine-functions.c +++ b/clang/test/Driver/fsplit-machine-functions.c @@ -1,9 +1,13 @@ -// RUN: %clang -### --target=x86_64 -fprofile-use=default.profdata -fsplit-machine-functions %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LTO-NEG -// RUN: %clang -### --target=aarch64 -fprofile-use=default.profdata -fsplit-machine-functions %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LTO-NEG -// RUN: %clang -### --target=x86_64 -fprofile-use=default.profdata -fsplit-machine-functions -fno-split-machine-functions %s -c 2>&1 | FileCheck -check-prefix=NEG %s +// RUN: rm -rf %t && mkdir %t +// RUN: llvm-profdata merge -o %t/default.profdata %S/Inputs/a.proftext + +// RUN: %clang -### --target=x86_64 -fprofile-use=%t/default.profdata -fsplit-machine-functions %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LTO-NEG +// RUN: %clang -### --target=aarch64 -fprofile-use=%t/default.profdata -fsplit-machine-functions %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LTO-NEG +// RUN: %clang -### --target=x86_64 -fprofile-use=%t/default.profdata -fsplit-machine-functions -fno-split-machine-functions %s -c 2>&1 | FileCheck -check-prefix=NEG %s // CHECK: "-fsplit-machine-functions" -// CHECK-SAME: "-fprofile-instrument-use-path=default.profdata" +// CHECK-SAME: "-fprofile-instrument-use=llvm" +// CHECK-SAME: "-fprofile-instrument-use-path={{.*}}default.profdata" // NEG-NOT: "-fsplit-machine-functions" diff --git a/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c b/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c index 173b43ba41bfe..0c7e96182aebf 100644 --- a/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c +++ b/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c @@ -15,7 +15,8 @@ // // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ -// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ +// RUN: -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata \ +// RUN: -Rpass=inline \ // RUN: -O1 \ // RUN: -Rpass-analysis=inline -Rpass-missed=inline \ // RUN: -fdiagnostics-show-hotness -verify @@ -34,24 +35,24 @@ // RUN: -verify // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ -// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ +// RUN: -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -O1 \ // RUN: -Rpass-analysis=inline -Rpass-missed=inline \ // RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 -verify // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ -// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ +// RUN: -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -O1 \ // RUN: -Rpass-analysis=inline 2>&1 | FileCheck -check-prefix=HOTNESS_OFF %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ -// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ +// RUN: -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -O1 \ // RUN: -Rpass-analysis=inline -Rno-pass-with-hotness 2>&1 | FileCheck \ // RUN: -check-prefix=HOTNESS_OFF %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ -// RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ +// RUN: -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -Rpass-analysis=inline -fdiagnostics-show-hotness \ // RUN: -fdiagnostics-hotness-threshold=100 2>&1 \ // RUN: | FileCheck -allow-empty -check-prefix=THRESHOLD %s diff --git a/clang/test/Profile/c-captured.c b/clang/test/Profile/c-captured.c index 3a802494eb6a6..e38798983b6c2 100644 --- a/clang/test/Profile/c-captured.c +++ b/clang/test/Profile/c-captured.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instrument=clang | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOGEN -check-prefix=PGOALL %s // RUN: llvm-profdata merge %S/Inputs/c-captured.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE -check-prefix=PGOALL %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE -check-prefix=PGOALL %s // PGOGEN: @[[DCC:__profc_debug_captured]] = private global [3 x i64] zeroinitializer // PGOGEN: @[[CSC:__profc_c_captured.c___captured_stmt]] = private global [2 x i64] zeroinitializer diff --git a/clang/test/Profile/c-counter-overflows.c b/clang/test/Profile/c-counter-overflows.c index 5cb32bbc30af4..bc12865b32b5d 100644 --- a/clang/test/Profile/c-counter-overflows.c +++ b/clang/test/Profile/c-counter-overflows.c @@ -2,7 +2,7 @@ // truncated. // RUN: llvm-profdata merge %S/Inputs/c-counter-overflows.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-counter-overflows.c %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-counter-overflows.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck %s typedef unsigned long long uint64_t; diff --git a/clang/test/Profile/c-general.c b/clang/test/Profile/c-general.c index 2f621ec9b0bf9..ee36a43dac081 100644 --- a/clang/test/Profile/c-general.c +++ b/clang/test/Profile/c-general.c @@ -3,11 +3,11 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument=clang | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOGEN %s // RUN: llvm-profdata merge %S/Inputs/c-general.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v5 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v3 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v5 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v3 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s // Also check compatibility with older profiles. -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v1 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v1 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s // RUN: %clang -fprofile-generate -E -dM %s | FileCheck -match-full-lines -check-prefix=PROFGENMACRO %s // RUN: %clang -fprofile-instr-generate -E -dM %s | FileCheck -match-full-lines -check-prefix=PROFGENMACRO %s diff --git a/clang/test/Profile/c-outdated-data.c b/clang/test/Profile/c-outdated-data.c index 454e4d799e0bb..7071401599b89 100644 --- a/clang/test/Profile/c-outdated-data.c +++ b/clang/test/Profile/c-outdated-data.c @@ -4,8 +4,8 @@ // doesn't play well with warnings that have no line number. // RUN: llvm-profdata merge %S/Inputs/c-outdated-data.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=NO_MISSING -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -Wprofile-instr-missing -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=WITH_MISSING +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=NO_MISSING +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -Wprofile-instr-missing -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -check-prefix=WITH_MISSING // NO_MISSING: warning: profile data may be out of date: of 3 functions, 2 have mismatched data that will be ignored // NO_MISSING-NOT: 1 has no data diff --git a/clang/test/Profile/c-unprofiled-blocks.c b/clang/test/Profile/c-unprofiled-blocks.c index e25bbc50de2ba..bcf3e06371e09 100644 --- a/clang/test/Profile/c-unprofiled-blocks.c +++ b/clang/test/Profile/c-unprofiled-blocks.c @@ -2,7 +2,7 @@ // runs) shouldn't have any branch weight metadata added. // RUN: llvm-profdata merge %S/Inputs/c-unprofiled-blocks.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled-blocks.c %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata | FileCheck -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled-blocks.c %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck -check-prefix=PGOUSE %s // PGOUSE-LABEL: @never_called(i32 noundef %i) int never_called(int i) { diff --git a/clang/test/Profile/c-unprofiled.c b/clang/test/Profile/c-unprofiled.c index 3466079f69bd8..3f52d773e1c06 100644 --- a/clang/test/Profile/c-unprofiled.c +++ b/clang/test/Profile/c-unprofiled.c @@ -7,7 +7,7 @@ // doesn't play well with warnings that have no line number. // RUN: llvm-profdata merge %S/Inputs/c-unprofiled.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled.c -I %S/Inputs/ %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata -Wprofile-instr-unprofiled 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled.c -I %S/Inputs/ %s -o /dev/null -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -Wprofile-instr-unprofiled 2>&1 | FileCheck %s // CHECK: warning: no profile data available for file "c-unprofiled.c" diff --git a/clang/test/Profile/cxx-class.cpp b/clang/test/Profile/cxx-class.cpp index c38a81e0d86e8..ce9ddcfc4553f 100644 --- a/clang/test/Profile/cxx-class.cpp +++ b/clang/test/Profile/cxx-class.cpp @@ -9,7 +9,7 @@ // RUN: FileCheck --input-file=%tgen -check-prefix=VDTRGEN %s // RUN: llvm-profdata merge %S/Inputs/cxx-class.proftext -o %t.profdata -// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -triple %itanium_abi_triple > %tuse +// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -triple %itanium_abi_triple > %tuse // RUN: FileCheck --input-file=%tuse -check-prefix=CTRUSE %s // RUN: FileCheck --input-file=%tuse -check-prefix=DTRUSE %s // RUN: FileCheck --input-file=%tuse -check-prefix=MTHUSE %s diff --git a/clang/test/Profile/cxx-hash-v2.cpp b/clang/test/Profile/cxx-hash-v2.cpp index 995fe008f5236..0696b20bdcac3 100644 --- a/clang/test/Profile/cxx-hash-v2.cpp +++ b/clang/test/Profile/cxx-hash-v2.cpp @@ -8,8 +8,8 @@ // RUN: diff %t.hashes %t.hashes.unique // RUN: llvm-profdata merge %S/Inputs/cxx-hash-v2.proftext -o %t.profdata -// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -allow-empty -// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use-path=%S/Inputs/cxx-hash-v2.profdata.v5 2>&1 | FileCheck %s -allow-empty +// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck %s -allow-empty +// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -triple x86_64-apple-macosx10.9 -main-file-name cxx-hash-v2.mm %s -o /dev/null -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%S/Inputs/cxx-hash-v2.profdata.v5 2>&1 | FileCheck %s -allow-empty // CHECK-NOT: warning: profile data may be out of date diff --git a/clang/test/Profile/cxx-lambda.cpp b/clang/test/Profile/cxx-lambda.cpp index 589f922c70782..b05fdd3d26b7c 100644 --- a/clang/test/Profile/cxx-lambda.cpp +++ b/clang/test/Profile/cxx-lambda.cpp @@ -5,7 +5,7 @@ // RUN: FileCheck -allow-deprecated-dag-overlap --input-file=%tgen -check-prefix=LMBGEN %s // RUN: llvm-profdata merge %S/Inputs/cxx-lambda.proftext -o %t.profdata -// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-lambda.cpp -std=c++11 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata > %tuse +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-lambda.cpp -std=c++11 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata > %tuse // RUN: FileCheck -allow-deprecated-dag-overlap --input-file=%tuse -check-prefix=PGOUSE %s // RUN: FileCheck -allow-deprecated-dag-overlap --input-file=%tuse -check-prefix=LMBUSE %s diff --git a/clang/test/Profile/cxx-missing-bodies.cpp b/clang/test/Profile/cxx-missing-bodies.cpp index 6d34fca482c99..87541c2825b25 100644 --- a/clang/test/Profile/cxx-missing-bodies.cpp +++ b/clang/test/Profile/cxx-missing-bodies.cpp @@ -2,7 +2,7 @@ // // Don't crash when presented profile data for functions without bodies: // RUN: llvm-profdata merge %S/Inputs/cxx-missing-bodies.proftext -o %t.profdata -// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only -triple=i386-pc-win32 -fno-rtti -fprofile-instrument-use-path=%t.profdata -w +// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only -triple=i386-pc-win32 -fno-rtti -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -w // GEN-NOT: __profn{{.*}}??_GA@@UAEPAXI@Z // GEN-NOT: __profn{{.*}}??_DA@@QAEXXZ diff --git a/clang/test/Profile/cxx-never-executed-branch.cpp b/clang/test/Profile/cxx-never-executed-branch.cpp index 812f65f3996d3..d7bdd3c67a15d 100644 --- a/clang/test/Profile/cxx-never-executed-branch.cpp +++ b/clang/test/Profile/cxx-never-executed-branch.cpp @@ -1,7 +1,7 @@ // Test that clang doesn't emit llvm.expect when the counter is 0 // RUN: llvm-profdata merge %S/Inputs/cxx-never-executed-branch.proftext -o %t.profdata -// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -disable-llvm-passes | FileCheck %s +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -disable-llvm-passes | FileCheck %s int rand(); diff --git a/clang/test/Profile/cxx-rangefor.cpp b/clang/test/Profile/cxx-rangefor.cpp index 58c578c3c1017..43bdaa9b70aeb 100644 --- a/clang/test/Profile/cxx-rangefor.cpp +++ b/clang/test/Profile/cxx-rangefor.cpp @@ -4,7 +4,7 @@ // RUN: FileCheck --input-file=%tgen -check-prefix=CHECK -check-prefix=PGOGEN %s // RUN: llvm-profdata merge %S/Inputs/cxx-rangefor.proftext -o %t.profdata -// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-rangefor.cpp -std=c++11 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata > %tuse +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-rangefor.cpp -std=c++11 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata > %tuse // RUN: FileCheck --input-file=%tuse -check-prefix=CHECK -check-prefix=PGOUSE %s // PGOGEN: @[[RFC:__profc__Z9range_forv]] = {{(private|internal)}} global [5 x i64] zeroinitializer diff --git a/clang/test/Profile/cxx-templates.cpp b/clang/test/Profile/cxx-templates.cpp index 51c8f1f6d1edd..09cf11e841dc4 100644 --- a/clang/test/Profile/cxx-templates.cpp +++ b/clang/test/Profile/cxx-templates.cpp @@ -6,7 +6,7 @@ // RUN: FileCheck --input-file=%tgen -check-prefix=T100GEN -check-prefix=ALL %s // RUN: llvm-profdata merge %S/Inputs/cxx-templates.proftext -o %t.profdata -// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-templates.cpp -std=c++11 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata > %tuse +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-templates.cpp -std=c++11 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata > %tuse // RUN: FileCheck --input-file=%tuse -check-prefix=T0USE -check-prefix=ALL %s // RUN: FileCheck --input-file=%tuse -check-prefix=T100USE -check-prefix=ALL %s diff --git a/clang/test/Profile/cxx-throws.cpp b/clang/test/Profile/cxx-throws.cpp index e989c2d39dfbb..fc04add24b97d 100644 --- a/clang/test/Profile/cxx-throws.cpp +++ b/clang/test/Profile/cxx-throws.cpp @@ -7,8 +7,8 @@ // RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument=clang -fexceptions -fcxx-exceptions -triple %itanium_abi_triple | FileCheck -check-prefix=PGOGEN-EXC %s // RUN: llvm-profdata merge %S/Inputs/cxx-throws.proftext -o %t.profdata -// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -fexceptions -fcxx-exceptions -triple %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s -// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -fexceptions -fcxx-exceptions -triple %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s +// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -fexceptions -fcxx-exceptions -triple %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s +// RUN: %clang_cc1 %s -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -fexceptions -fcxx-exceptions -triple %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s // PGOGEN: @[[THC:__profc__Z6throwsv]] = {{(private|internal)}} global [9 x i64] zeroinitializer // PGOGEN-EXC: @[[THC:__profc__Z6throwsv]] = {{(private|internal)}} global [9 x i64] zeroinitializer diff --git a/clang/test/Profile/func-entry.c b/clang/test/Profile/func-entry.c index 4a4ca2288352b..27d11cc254ea8 100644 --- a/clang/test/Profile/func-entry.c +++ b/clang/test/Profile/func-entry.c @@ -1,7 +1,7 @@ // Test that function entry counts are set correctly. // RUN: llvm-profdata merge %S/Inputs/func-entry.proftext -o %t.profdata -// RUN: %clang_cc1 %s -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata | FileCheck %s +// RUN: %clang_cc1 %s -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck %s void foo(void); diff --git a/clang/test/Profile/misexpect-branch-cold.c b/clang/test/Profile/misexpect-branch-cold.c index 6d34f92a25454..43ef3fcdda0ba 100644 --- a/clang/test/Profile/misexpect-branch-cold.c +++ b/clang/test/Profile/misexpect-branch-cold.c @@ -1,7 +1,7 @@ // Test that misexpect emits no warning when prediction is correct // RUN: llvm-profdata merge %S/Inputs/misexpect-branch.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect +// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect // expected-no-diagnostics #define likely(x) __builtin_expect(!!(x), 1) diff --git a/clang/test/Profile/misexpect-branch-nonconst-expected-val.c b/clang/test/Profile/misexpect-branch-nonconst-expected-val.c index c5167b9a2a0b7..fa2b4f1755040 100644 --- a/clang/test/Profile/misexpect-branch-nonconst-expected-val.c +++ b/clang/test/Profile/misexpect-branch-nonconst-expected-val.c @@ -1,7 +1,7 @@ // Test that misexpect emits no warning when condition is not a compile-time constant // RUN: llvm-profdata merge %S/Inputs/misexpect-branch-nonconst-expect-arg.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect +// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect // expected-no-diagnostics int foo(int); diff --git a/clang/test/Profile/misexpect-branch-unpredictable.c b/clang/test/Profile/misexpect-branch-unpredictable.c index 6c4f90146a2ae..ffaf25aed82bd 100644 --- a/clang/test/Profile/misexpect-branch-unpredictable.c +++ b/clang/test/Profile/misexpect-branch-unpredictable.c @@ -1,7 +1,7 @@ // Test that misexpect emits no warning when prediction is correct // RUN: llvm-profdata merge %S/Inputs/misexpect-branch.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect +// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect // expected-no-diagnostics #define unpredictable(x) __builtin_unpredictable(!!(x)) diff --git a/clang/test/Profile/misexpect-branch.c b/clang/test/Profile/misexpect-branch.c index 5c4394405e178..fb7225047fcb0 100644 --- a/clang/test/Profile/misexpect-branch.c +++ b/clang/test/Profile/misexpect-branch.c @@ -2,12 +2,12 @@ // test diagnostics are issued when profiling data mis-matches annotations // RUN: llvm-profdata merge %S/Inputs/misexpect-branch.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify=imprecise -Wmisexpect -// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify=exact -Wmisexpect -debug-info-kind=line-tables-only +// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify=imprecise -Wmisexpect +// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify=exact -Wmisexpect -debug-info-kind=line-tables-only // there should be no diagnostics when the tolerance is sufficiently high, or when -Wmisexpect is not requested -// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify=foo -fdiagnostics-misexpect-tolerance=10 -Wmisexpect -debug-info-kind=line-tables-only -// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify=foo +// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify=foo -fdiagnostics-misexpect-tolerance=10 -Wmisexpect -debug-info-kind=line-tables-only +// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify=foo // Ensure we emit an error when we don't use pgo with tolerance threshold // RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fdiagnostics-misexpect-tolerance=10 -Wmisexpect -debug-info-kind=line-tables-only 2>&1 | FileCheck -check-prefix=NO_PGO %s diff --git a/clang/test/Profile/misexpect-switch-default.c b/clang/test/Profile/misexpect-switch-default.c index cd337b9430171..89eb64fea420b 100644 --- a/clang/test/Profile/misexpect-switch-default.c +++ b/clang/test/Profile/misexpect-switch-default.c @@ -1,7 +1,7 @@ // Test that misexpect detects mis-annotated switch statements for default case // RUN: llvm-profdata merge %S/Inputs/misexpect-switch-default.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect -debug-info-kind=line-tables-only +// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect -debug-info-kind=line-tables-only #define inner_loop 1000 #define outer_loop 20 diff --git a/clang/test/Profile/misexpect-switch-nonconst.c b/clang/test/Profile/misexpect-switch-nonconst.c index cff3bce0d6d0a..f18baea83cc1d 100644 --- a/clang/test/Profile/misexpect-switch-nonconst.c +++ b/clang/test/Profile/misexpect-switch-nonconst.c @@ -1,7 +1,7 @@ // Test that misexpect emits no warning when switch condition is non-const // RUN: llvm-profdata merge %S/Inputs/misexpect-switch-nonconst.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify +// RUN: %clang_cc1 %s -O2 -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify // expected-no-diagnostics diff --git a/clang/test/Profile/misexpect-switch-only-default-case.c b/clang/test/Profile/misexpect-switch-only-default-case.c index 26e8564c81b54..ef0f124305625 100644 --- a/clang/test/Profile/misexpect-switch-only-default-case.c +++ b/clang/test/Profile/misexpect-switch-only-default-case.c @@ -1,7 +1,7 @@ // Test that misexpect emits no warning when there is only one switch case // RUN: llvm-profdata merge %S/Inputs/misexpect-switch-default-only.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect -debug-info-kind=line-tables-only +// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect -debug-info-kind=line-tables-only // expected-no-diagnostics diff --git a/clang/test/Profile/misexpect-switch.c b/clang/test/Profile/misexpect-switch.c index 84a7174f635fd..ae13cf7675706 100644 --- a/clang/test/Profile/misexpect-switch.c +++ b/clang/test/Profile/misexpect-switch.c @@ -1,7 +1,7 @@ // Test that misexpect detects mis-annotated switch statements // RUN: llvm-profdata merge %S/Inputs/misexpect-switch.proftext -o %t.profdata -// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect -debug-info-kind=line-tables-only +// RUN: %clang_cc1 %s -O2 -o - -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata -verify -Wmisexpect -debug-info-kind=line-tables-only #define inner_loop 1000 #define outer_loop 20 diff --git a/clang/test/Profile/objc-general.m b/clang/test/Profile/objc-general.m index a3dcb1b2128c6..a711645e7c833 100644 --- a/clang/test/Profile/objc-general.m +++ b/clang/test/Profile/objc-general.m @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument=clang | FileCheck -check-prefix=PGOGEN %s // RUN: llvm-profdata merge %S/Inputs/objc-general.proftext -o %t.profdata -// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck -check-prefix=PGOUSE %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata 2>&1 | FileCheck -check-prefix=PGOUSE %s // PGOUSE-NOT: warning: profile data may be out of date diff --git a/clang/test/Profile/profile-does-not-exist-ir.c b/clang/test/Profile/profile-does-not-exist-ir.c index 842a3d44a387b..cb7bef2b7043b 100644 --- a/clang/test/Profile/profile-does-not-exist-ir.c +++ b/clang/test/Profile/profile-does-not-exist-ir.c @@ -1,4 +1,8 @@ -// RUN: not %clang_cc1 -emit-llvm -x ir %s -o - -fprofile-instrument-use-path=%t.nonexistent.profdata 2>&1 | FileCheck %s +; RUN: not %clang_cc1 -emit-llvm -x ir %s -o - -fprofile-instrument-use=llvm -fprofile-instrument-use-path=%t.nonexistent.profdata 2>&1 | FileCheck %s -// CHECK: error: Error in reading profile {{.*}}.nonexistent.profdata: -// CHECK-NOT: Assertion failed +; CHECK: error: {{.*}}.nonexistent.profdata: +; CHECK-NOT: Assertion failed + +define i32 @main() { + ret i32 0 +} diff --git a/clang/test/Profile/profile-does-not-exist.c b/clang/test/Profile/profile-does-not-exist.c index 88d55d8668ef8..e9e04bed19b84 100644 --- a/clang/test/Profile/profile-does-not-exist.c +++ b/clang/test/Profile/profile-does-not-exist.c @@ -1,4 +1,8 @@ -// RUN: not %clang_cc1 -emit-llvm %s -o - -fprofile-instrument-use-path=%t.nonexistent.profdata 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -emit-llvm %s -o - -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.nonexistent.profdata 2>&1 | FileCheck %s // CHECK: error: Error in reading profile {{.*}}.nonexistent.profdata: // CHECK-NOT: Assertion failed + +int main() { + return 0; +} diff --git a/clang/test/Profile/profile-summary.c b/clang/test/Profile/profile-summary.c index 47fd9e85a4539..31e8497ed6398 100644 --- a/clang/test/Profile/profile-summary.c +++ b/clang/test/Profile/profile-summary.c @@ -1,7 +1,7 @@ // Test that profile summary is set correctly. // RUN: llvm-profdata merge %S/Inputs/max-function-count.proftext -o %t.profdata -// RUN: %clang_cc1 %s -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use-path=%t.profdata | FileCheck %s +// RUN: %clang_cc1 %s -o - -disable-llvm-passes -emit-llvm -fprofile-instrument-use=clang -fprofile-instrument-use-path=%t.profdata | FileCheck %s // int begin(int i) { if (i) From c2250e3f4946ebd49535d71831cc68bcc194640c Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 15 Oct 2025 09:24:36 -0700 Subject: [PATCH 39/41] [support] Use VFS in `SourceMgr` for loading includes (#162903) Most `SourceMgr` clients don't make use of include files, but those that do might want to specify the file system to use. This patch enables that by making it possible to pass a `vfs::FileSystem` instance into `SourceMgr`. --- clang/tools/driver/cc1as_main.cpp | 11 +++++++---- llvm/include/llvm/CodeGen/AsmPrinter.h | 8 ++++++++ llvm/include/llvm/Support/SourceMgr.h | 11 +++++++---- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 ++ .../CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | 2 ++ llvm/lib/Support/SourceMgr.cpp | 18 +++++++++++------- llvm/lib/TableGen/Main.cpp | 2 ++ llvm/lib/TableGen/Parser.cpp | 2 ++ .../llvm-mc-assemble-fuzzer.cpp | 2 ++ llvm/tools/llvm-mc/llvm-mc.cpp | 2 ++ llvm/tools/llvm-ml/llvm-ml.cpp | 2 ++ llvm/unittests/Support/SourceMgrTest.cpp | 10 ++++++++++ mlir/lib/IR/Diagnostics.cpp | 6 ++++-- mlir/lib/Tools/PDLL/Parser/Parser.cpp | 2 ++ .../Tools/mlir-pdll-lsp-server/PDLLServer.cpp | 2 ++ .../Tools/tblgen-lsp-server/TableGenServer.cpp | 2 ++ mlir/tools/mlir-pdll/mlir-pdll.cpp | 2 ++ 17 files changed, 69 insertions(+), 17 deletions(-) diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index d2244e572d55e..207f9f11c4de9 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -429,7 +429,8 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) { } static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, - DiagnosticsEngine &Diags) { + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr VFS) { // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error); @@ -452,6 +453,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, // Record the location of the include directories so that the lexer can find // it later. SrcMgr.setIncludeDirs(Opts.IncludePaths); + SrcMgr.setVirtualFileSystem(VFS); std::unique_ptr MRI(TheTarget->createMCRegInfo(Opts.Triple)); assert(MRI && "Unable to create target register info!"); @@ -647,8 +649,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, } static bool ExecuteAssembler(AssemblerInvocation &Opts, - DiagnosticsEngine &Diags) { - bool Failed = ExecuteAssemblerImpl(Opts, Diags); + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr VFS) { + bool Failed = ExecuteAssemblerImpl(Opts, Diags, VFS); // Delete output file if there were errors. if (Failed) { @@ -730,7 +733,7 @@ int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { } // Execute the invocation, unless there were parsing errors. - bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags); + bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags, VFS); // If any timers were active but haven't been destroyed yet, print their // results now. diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index dafe887bc0f3b..0982820e69a35 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -16,6 +16,7 @@ #define LLVM_CODEGEN_ASMPRINTER_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/ProfileSummaryInfo.h" @@ -88,6 +89,10 @@ namespace remarks { class RemarkStreamer; } +namespace vfs { +class FileSystem; +} + /// This class is intended to be used as a driving class for all asm writers. class LLVM_ABI AsmPrinter : public MachineFunctionPass { public: @@ -106,6 +111,9 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { /// generating (such as the current section etc). std::unique_ptr OutStreamer; + /// The VFS to resolve asm include directives. + IntrusiveRefCntPtr VFS; + /// The current machine function. MachineFunction *MF = nullptr; diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h index e4a27ade1f6bb..8320006ff5f6e 100644 --- a/llvm/include/llvm/Support/SourceMgr.h +++ b/llvm/include/llvm/Support/SourceMgr.h @@ -96,22 +96,25 @@ class SourceMgr { DiagHandlerTy DiagHandler = nullptr; void *DiagContext = nullptr; - // Filesystem for finding includes, if not the real FS. + // Optional file system for finding include files. IntrusiveRefCntPtr FS; bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); } public: + /// Create new source manager without support for include files. SourceMgr(); + /// Create new source manager with the capability of finding include files + /// via the provided file system. + explicit SourceMgr(IntrusiveRefCntPtr FS); SourceMgr(const SourceMgr &) = delete; SourceMgr &operator=(const SourceMgr &) = delete; SourceMgr(SourceMgr &&); SourceMgr &operator=(SourceMgr &&); ~SourceMgr(); - /// Specify a \a vfs::FileSystem for finding includes. - explicit SourceMgr(IntrusiveRefCntPtr FS); - void setFileSystem(IntrusiveRefCntPtr FS); + IntrusiveRefCntPtr getVirtualFileSystem() const; + void setVirtualFileSystem(IntrusiveRefCntPtr FS); /// Return the include directories of this source manager. ArrayRef getIncludeDirs() const { return IncludeDirectories; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index be0a1c3b0a0c2..725d362ebe4c6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -117,6 +117,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/VCSRevision.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" @@ -463,6 +464,7 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { } bool AsmPrinter::doInitialization(Module &M) { + VFS = vfs::getRealFileSystem(); auto *MMIWP = getAnalysisIfAvailable(); MMI = MMIWP ? &MMIWP->getMMI() : nullptr; HasSplitStack = false; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index c364ffc6eb8c1..8dd8b9da9c50c 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -98,6 +99,7 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode); SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager(); SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths); + SrcMgr.setVirtualFileSystem(VFS); std::unique_ptr Parser( createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum)); diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp index 4a69ccc7605bc..708b7668ed7a0 100644 --- a/llvm/lib/Support/SourceMgr.cpp +++ b/llvm/lib/Support/SourceMgr.cpp @@ -41,14 +41,17 @@ static const size_t TabStop = 8; // Out of line to avoid needing definition of vfs::FileSystem in header. SourceMgr::SourceMgr() = default; -SourceMgr::~SourceMgr() = default; +SourceMgr::SourceMgr(IntrusiveRefCntPtr FS) + : FS(std::move(FS)) {} SourceMgr::SourceMgr(SourceMgr &&) = default; SourceMgr &SourceMgr::operator=(SourceMgr &&) = default; +SourceMgr::~SourceMgr() = default; -SourceMgr::SourceMgr(IntrusiveRefCntPtr FS) - : FS(std::move(FS)) {} +IntrusiveRefCntPtr SourceMgr::getVirtualFileSystem() const { + return FS; +} -void SourceMgr::setFileSystem(IntrusiveRefCntPtr FS) { +void SourceMgr::setVirtualFileSystem(IntrusiveRefCntPtr FS) { this->FS = std::move(FS); } @@ -66,10 +69,11 @@ unsigned SourceMgr::AddIncludeFile(const std::string &Filename, ErrorOr> SourceMgr::OpenIncludeFile(const std::string &Filename, std::string &IncludedFile) { - auto getFile = [this](StringRef Path) { + auto GetFile = [this](StringRef Path) { return FS ? FS->getBufferForFile(Path) : MemoryBuffer::getFile(Path); }; - ErrorOr> NewBufOrErr = getFile(Filename); + + ErrorOr> NewBufOrErr = GetFile(Filename); SmallString<64> Buffer(Filename); // If the file didn't exist directly, see if it's in an include path. @@ -77,7 +81,7 @@ SourceMgr::OpenIncludeFile(const std::string &Filename, ++i) { Buffer = IncludeDirectories[i]; sys::path::append(Buffer, Filename); - NewBufOrErr = getFile(Buffer); + NewBufOrErr = GetFile(Buffer); } if (NewBufOrErr) diff --git a/llvm/lib/TableGen/Main.cpp b/llvm/lib/TableGen/Main.cpp index f545706d6fe30..ce43123da883c 100644 --- a/llvm/lib/TableGen/Main.cpp +++ b/llvm/lib/TableGen/Main.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -130,6 +131,7 @@ int llvm::TableGenMain(const char *argv0, // Record the location of the include directory so that the lexer can find // it later. SrcMgr.setIncludeDirs(IncludeDirs); + SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem()); TGParser Parser(SrcMgr, MacroNames, Records, NoWarnOnUnusedTemplateArgs); diff --git a/llvm/lib/TableGen/Parser.cpp b/llvm/lib/TableGen/Parser.cpp index 2c3726a339bb8..db45054061524 100644 --- a/llvm/lib/TableGen/Parser.cpp +++ b/llvm/lib/TableGen/Parser.cpp @@ -9,6 +9,7 @@ #include "llvm/TableGen/Parser.h" #include "TGParser.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/TableGen/Record.h" using namespace llvm; @@ -21,6 +22,7 @@ bool llvm::TableGenParseFile(SourceMgr &InputSrcMgr, RecordKeeper &Records) { SrcMgr = SourceMgr(); SrcMgr.takeSourceBuffersFrom(InputSrcMgr); SrcMgr.setIncludeDirs(InputSrcMgr.getIncludeDirs()); + SrcMgr.setVirtualFileSystem(InputSrcMgr.getVirtualFileSystem()); SrcMgr.setDiagHandler(InputSrcMgr.getDiagHandler(), InputSrcMgr.getDiagContext()); diff --git a/llvm/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp b/llvm/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp index 615a39ee9bb4d..5b4d3cd13c2b8 100644 --- a/llvm/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp +++ b/llvm/tools/llvm-mc-assemble-fuzzer/llvm-mc-assemble-fuzzer.cpp @@ -31,6 +31,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/SubtargetFeature.h" @@ -142,6 +143,7 @@ int AssembleOneInput(const uint8_t *Data, size_t Size) { static const std::vector NoIncludeDirs; SrcMgr.setIncludeDirs(NoIncludeDirs); + SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem()); static std::string ArchName; std::string Error; diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp index fd7fd399d15af..b5746fdeb7a00 100644 --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -41,6 +41,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/WithColor.h" #include "llvm/TargetParser/Host.h" #include @@ -434,6 +435,7 @@ int main(int argc, char **argv) { // Record the location of the include directories so that the lexer can find // it later. SrcMgr.setIncludeDirs(IncludeDirs); + SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem()); std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); diff --git a/llvm/tools/llvm-ml/llvm-ml.cpp b/llvm/tools/llvm-ml/llvm-ml.cpp index c8e49edd34e04..504ac9d12486d 100644 --- a/llvm/tools/llvm-ml/llvm-ml.cpp +++ b/llvm/tools/llvm-ml/llvm-ml.cpp @@ -41,6 +41,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/WithColor.h" #include "llvm/TargetParser/Host.h" #include @@ -315,6 +316,7 @@ int llvm_ml_main(int Argc, char **Argv, const llvm::ToolContext &) { } } SrcMgr.setIncludeDirs(IncludeDirs); + SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem()); std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); diff --git a/llvm/unittests/Support/SourceMgrTest.cpp b/llvm/unittests/Support/SourceMgrTest.cpp index 41d09ab5adc75..8121d339f6fa4 100644 --- a/llvm/unittests/Support/SourceMgrTest.cpp +++ b/llvm/unittests/Support/SourceMgrTest.cpp @@ -566,3 +566,13 @@ TEST_F(SourceMgrTest, PrintWithoutLoc) { Diag.print(nullptr, OS, false, false, false); EXPECT_EQ("message\n", Output); } + +TEST_F(SourceMgrTest, IncludeDirs) { + auto VFS = makeIntrusiveRefCnt(); + VFS->addFile("include/file", 0, MemoryBuffer::getMemBuffer("contents")); + SM.setVirtualFileSystem(std::move(VFS)); + SM.setIncludeDirs({"include"}); + std::string ResolvedPath; + unsigned NumBuffers = SM.AddIncludeFile("file", SMLoc(), ResolvedPath); + EXPECT_EQ(NumBuffers, 1u); +} diff --git a/mlir/lib/IR/Diagnostics.cpp b/mlir/lib/IR/Diagnostics.cpp index 3e337951bcd3f..2467441eb7071 100644 --- a/mlir/lib/IR/Diagnostics.cpp +++ b/mlir/lib/IR/Diagnostics.cpp @@ -378,8 +378,10 @@ struct SourceMgrDiagnosticHandlerImpl { } // Otherwise, try to load the source file. - std::string ignored; - unsigned id = mgr.AddIncludeFile(std::string(filename), SMLoc(), ignored); + auto bufferOrErr = llvm::MemoryBuffer::getFile(filename); + if (!bufferOrErr) + return 0; + unsigned id = mgr.AddNewSourceBuffer(std::move(*bufferOrErr), SMLoc()); filenameToBufId[filename] = id; return id; } diff --git a/mlir/lib/Tools/PDLL/Parser/Parser.cpp b/mlir/lib/Tools/PDLL/Parser/Parser.cpp index 50e10447ee468..f6d665b6e0162 100644 --- a/mlir/lib/Tools/PDLL/Parser/Parser.cpp +++ b/mlir/lib/Tools/PDLL/Parser/Parser.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Parser.h" #include @@ -828,6 +829,7 @@ LogicalResult Parser::parseTdInclude(StringRef filename, llvm::SMRange fileLoc, llvm::SourceMgr tdSrcMgr; tdSrcMgr.AddNewSourceBuffer(std::move(*includeBuffer), SMLoc()); tdSrcMgr.setIncludeDirs(parserSrcMgr.getIncludeDirs()); + tdSrcMgr.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); // This class provides a context argument for the llvm::SourceMgr diagnostic // handler. diff --git a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp index 84f529ae16401..acc84a8b98f2f 100644 --- a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp +++ b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp @@ -31,6 +31,7 @@ #include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include using namespace mlir; @@ -389,6 +390,7 @@ PDLDocument::PDLDocument(const lsp::URIForFile &uri, StringRef contents, llvm::append_range(includeDirs, extraDirs); sourceMgr.setIncludeDirs(includeDirs); + sourceMgr.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc()); astContext.getDiagEngine().setHandlerFn([&](const ast::Diagnostic &diag) { diff --git a/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp b/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp index 5faeeae839f44..fa30674282394 100644 --- a/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp +++ b/mlir/lib/Tools/tblgen-lsp-server/TableGenServer.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/TableGen/Parser.h" #include "llvm/TableGen/Record.h" #include @@ -437,6 +438,7 @@ void TableGenTextFile::initialize(const lsp::URIForFile &uri, return; } sourceMgr.setIncludeDirs(includeDirs); + sourceMgr.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc()); // This class provides a context argument for the SourceMgr diagnostic diff --git a/mlir/tools/mlir-pdll/mlir-pdll.cpp b/mlir/tools/mlir-pdll/mlir-pdll.cpp index 88a5f3639c962..905becd7745f3 100644 --- a/mlir/tools/mlir-pdll/mlir-pdll.cpp +++ b/mlir/tools/mlir-pdll/mlir-pdll.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include using namespace mlir; @@ -41,6 +42,7 @@ processBuffer(raw_ostream &os, std::unique_ptr chunkBuffer, bool dumpODS, std::set *includedFiles) { llvm::SourceMgr sourceMgr; sourceMgr.setIncludeDirs(includeDirs); + sourceMgr.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); sourceMgr.AddNewSourceBuffer(std::move(chunkBuffer), SMLoc()); // If we are dumping ODS information, also enable documentation to ensure the From 3d9d9e7820942176aa6b885502603cb28028119f Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Sat, 18 Oct 2025 18:42:13 -0700 Subject: [PATCH 40/41] [clang] Fix buggy FileManager setter --- clang/lib/Frontend/CompilerInstance.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 593bca1d281e7..b73095f076fe1 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -173,10 +173,13 @@ bool CompilerInstance::createTarget() { } void CompilerInstance::setFileManager(FileManager *Value) { - if (!hasVirtualFileSystem()) - setVirtualFileSystem(Value->getVirtualFileSystemPtr()); - assert(Value == nullptr || - getVirtualFileSystemPtr() == Value->getVirtualFileSystemPtr()); + if (Value == nullptr) { + FileMgr = nullptr; + return; + } + if (VFS == nullptr) + VFS = Value->getVirtualFileSystemPtr(); + assert(VFS == Value->getVirtualFileSystemPtr()); FileMgr = Value; } From 6980f6eb3ed382f4d86a4861289e509014aff8d1 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Sun, 19 Oct 2025 21:10:37 -0700 Subject: [PATCH 41/41] [clang] Experimental fix to assertion failure on Windows --- clang/lib/Frontend/FrontendAction.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index ff5a8014b2f74..ca54599b41613 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -985,6 +985,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. + CI.setVirtualFileSystem(AST->getFileManager().getVirtualFileSystemPtr()); CI.setFileManager(&AST->getFileManager()); CI.setSourceManager(&AST->getSourceManager()); CI.setPreprocessor(AST->getPreprocessorPtr());