https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/184376
>From 2dae7abb05404e19af480ace773b5b6c694484f5 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Mon, 2 Mar 2026 08:26:15 -0800 Subject: [PATCH 1/4] Lift by-name Worker APIs to Tool --- .../DependencyScanningWorker.h | 40 ------------------- .../clang/Tooling/DependencyScanningTool.h | 7 ++-- .../DependencyScanningWorker.cpp | 28 ------------- clang/lib/Tooling/DependencyScanningTool.cpp | 33 +++++++++------ 4 files changed, 24 insertions(+), 84 deletions(-) diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h index 9267c25c93ee9..5506d9f78d9fc 100644 --- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h @@ -125,45 +125,6 @@ class DependencyScanningWorker { llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS = nullptr); - /// The two method below implements a new interface for by name - /// dependency scanning. They together enable the dependency scanning worker - /// to more effectively perform scanning for a sequence of modules - /// by name when the CWD and CommandLine do not change across the queries. - /// The initialization function asks the client for a DiagnosticsConsumer - /// that it direct the diagnostics to. - - /// @brief Initializing the context and the compiler instance. - /// @param CWD The current working directory used during the scan. - /// @param CommandLine The commandline used for the scan. - /// @return False if the initializaiton fails. - bool initializeCompilerInstanceWithContext(StringRef CWD, - ArrayRef<std::string> CommandLine, - DiagnosticConsumer &DC); - - /// @brief Initializing the context and the compiler instance. - /// @param CWD The current working directory used during the scan. - /// @param CommandLine The commandline used for the scan. - /// @param DiagEngineWithCmdAndOpts Preconfigured diagnostics engine and - /// options associated with the cc1 command line. - /// @param FS The overlay file system to use for this compiler instance. - /// @return False if the initializaiton fails. - bool initializeCompilerInstanceWithContext( - StringRef CWD, ArrayRef<std::string> CommandLine, - std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts, - IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS); - - /// @brief Performaces dependency scanning for the module whose name is - /// specified. - /// @param ModuleName The name of the module whose dependency will be - /// scanned. - /// @param Consumer The dependency consumer that stores the results. - /// @param Controller The controller for the dependency scanning action. - /// @return False if the scanner incurs errors. - bool - computeDependenciesByNameWithContext(StringRef ModuleName, - DependencyConsumer &Consumer, - DependencyActionController &Controller); - llvm::vfs::FileSystem &getVFS() const { return *DepFS; } private: @@ -175,7 +136,6 @@ class DependencyScanningWorker { IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; friend CompilerInstanceWithContext; - std::unique_ptr<CompilerInstanceWithContext> CIWithContext; }; std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h index cd7bab37bd917..694c1cb2a1f72 100644 --- a/clang/include/clang/Tooling/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanningTool.h @@ -147,10 +147,10 @@ class DependencyScanningTool { llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); } - /// @brief Initialize the worker's compiler instance from the commandline. + /// @brief Initialize the tool's compiler instance from the commandline. /// The compiler instance only takes a `-cc1` job, so this method /// builds the `-cc1` job from the CommandLine input. - /// @param Worker The dependency scanning worker whose compiler instance + /// @param Tool The dependency scanning tool whose compiler instance /// with context is initialized. /// @param CWD The current working directory. /// @param CommandLine This command line may be a driver command or a cc1 @@ -158,13 +158,14 @@ class DependencyScanningTool { /// @param DC A diagnostics consumer to report error if the initialization /// fails. static bool initializeWorkerCIWithContextFromCommandline( - clang::dependencies::DependencyScanningWorker &Worker, StringRef CWD, + DependencyScanningTool &Tool, StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC); private: dependencies::DependencyScanningWorker Worker; std::unique_ptr<dependencies::TextDiagnosticsPrinterWithOutput> DiagPrinterWithOS; + std::unique_ptr<dependencies::CompilerInstanceWithContext> CIWithContext; }; /// Run the dependency scanning worker for the given driver or frontend diff --git a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp index 4c24642c437c3..7a7f34a43b338 100644 --- a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp @@ -109,34 +109,6 @@ bool DependencyScanningWorker::computeDependencies( return Success && Action.hasScanned(); } -bool DependencyScanningWorker::initializeCompilerInstanceWithContext( - StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) { - auto [OverlayFS, ModifiedCommandLine] = - initVFSForByNameScanning(DepFS, CommandLine, CWD, "ScanningByName"); - auto DiagEngineWithCmdAndOpts = - std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine, - OverlayFS, DC); - return initializeCompilerInstanceWithContext( - CWD, ModifiedCommandLine, std::move(DiagEngineWithCmdAndOpts), OverlayFS); -} - -bool DependencyScanningWorker::initializeCompilerInstanceWithContext( - StringRef CWD, ArrayRef<std::string> CommandLine, - std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, - IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS) { - CIWithContext = - std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine); - return CIWithContext->initialize(std::move(DiagEngineWithDiagOpts), - OverlayFS); -} - -bool DependencyScanningWorker::computeDependenciesByNameWithContext( - StringRef ModuleName, DependencyConsumer &Consumer, - DependencyActionController &Controller) { - assert(CIWithContext && "CompilerInstance with context required!"); - return CIWithContext->computeDependencies(ModuleName, Consumer, Controller); -} - std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, std::vector<std::string>> dependencies::initVFSForTUBufferScanning( diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index 26f07286f18c4..79a84f0148fcf 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -313,30 +313,37 @@ static std::optional<SmallVector<std::string, 0>> getFirstCC1CommandLine( } bool DependencyScanningTool::initializeWorkerCIWithContextFromCommandline( - DependencyScanningWorker &Worker, StringRef CWD, + DependencyScanningTool &Tool, StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) { + auto [OverlayFS, ModifiedCommandLine] = initVFSForByNameScanning( + &Tool.Worker.getVFS(), CommandLine, CWD, "ScanningByName"); + auto DiagEngineWithCmdAndOpts = + std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine, + OverlayFS, DC); + if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") { // The input command line is already a -cc1 invocation; initialize the // compiler instance directly from it. - return Worker.initializeCompilerInstanceWithContext(CWD, CommandLine, DC); + Tool.CIWithContext = std::make_unique<CompilerInstanceWithContext>( + Tool.Worker, CWD, CommandLine); + return Tool.CIWithContext->initialize(std::move(DiagEngineWithCmdAndOpts), + OverlayFS); } // The input command line is either a driver-style command line, or // ill-formed. In this case, we will first call the Driver to build a -cc1 // command line for this compilation or diagnose any ill-formed input. - auto [OverlayFS, ModifiedCommandLine] = initVFSForByNameScanning( - &Worker.getVFS(), CommandLine, CWD, "ScanningByName"); - auto DiagEngineWithCmdAndOpts = - std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine, - OverlayFS, DC); - const auto MaybeFirstCC1 = getFirstCC1CommandLine( ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS); if (!MaybeFirstCC1) return false; - return Worker.initializeCompilerInstanceWithContext( - CWD, *MaybeFirstCC1, std::move(DiagEngineWithCmdAndOpts), OverlayFS); + std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(), + MaybeFirstCC1->end()); + Tool.CIWithContext = std::make_unique<CompilerInstanceWithContext>( + Tool.Worker, CWD, std::move(CC1CommandLine)); + return Tool.CIWithContext->initialize(std::move(DiagEngineWithCmdAndOpts), + OverlayFS); } llvm::Error @@ -346,7 +353,7 @@ DependencyScanningTool::initializeCompilerInstanceWithContextOrError( std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine); bool Result = initializeWorkerCIWithContextFromCommandline( - Worker, CWD, CommandLine, DiagPrinterWithOS->DiagPrinter); + *this, CWD, CommandLine, DiagPrinterWithOS->DiagPrinter); if (Result) return llvm::Error::success(); @@ -362,8 +369,8 @@ DependencyScanningTool::computeDependenciesByNameWithContextOrError( // We need to clear the DiagnosticOutput so that each by-name lookup // has a clean diagnostics buffer. DiagPrinterWithOS->DiagnosticOutput.clear(); - if (Worker.computeDependenciesByNameWithContext(ModuleName, Consumer, - Controller)) + assert(CIWithContext && "CompilerInstance with context required!"); + if (CIWithContext->computeDependencies(ModuleName, Consumer, Controller)) return Consumer.takeTranslationUnitDeps(); return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } >From 4d37c3fa15d5da4d7c34ce5f82da0803d0d3454f Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Mon, 2 Mar 2026 09:30:55 -0800 Subject: [PATCH 2/4] Expose implementation functions in the header --- .../DependencyScanning/DependencyScannerImpl.h | 13 +++++++++++++ .../DependencyScannerImpl.cpp | 18 +++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h index 4210c20942a32..716d69f19347c 100644 --- a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h +++ b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h @@ -91,6 +91,19 @@ std::unique_ptr<CompilerInvocation> createCompilerInvocation(ArrayRef<std::string> CommandLine, DiagnosticsEngine &Diags); +/// Canonicalizes command-line macro defines (e.g. removing "-DX -UX"). +void canonicalizeDefines(PreprocessorOptions &PPOpts); + +/// Creates a CompilerInvocation suitable for the dependency scanner. +std::shared_ptr<CompilerInvocation> +createScanCompilerInvocation(const CompilerInvocation &Invocation, + const DependencyScanningService &Service); + +/// Creates dependency output options to be reported to the dependency consumer, +/// deducing missing information if necessary. +std::unique_ptr<DependencyOutputOptions> +createDependencyOutputOptions(const CompilerInvocation &Invocation); + void initializeScanCompilerInstance( CompilerInstance &ScanInstance, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp index 3e680f4b4b363..9aeae580711f7 100644 --- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp @@ -285,8 +285,9 @@ static std::optional<StringRef> getSimpleMacroName(StringRef Macro) { } return FinishName(); } +} // namespace -static void canonicalizeDefines(PreprocessorOptions &PPOpts) { +void dependencies::canonicalizeDefines(PreprocessorOptions &PPOpts) { using MacroOpt = std::pair<StringRef, std::size_t>; std::vector<MacroOpt> SimpleNames; SimpleNames.reserve(PPOpts.Macros.size()); @@ -318,6 +319,7 @@ static void canonicalizeDefines(PreprocessorOptions &PPOpts) { std::swap(PPOpts.Macros, NewMacros); } +namespace { class ScanningDependencyDirectivesGetter : public DependencyDirectivesGetter { DependencyScanningWorkerFilesystem *DepFS; @@ -430,10 +432,9 @@ void dependencies::initializeScanCompilerInstance( } } -/// Creates a CompilerInvocation suitable for the dependency scanner. -static std::shared_ptr<CompilerInvocation> -createScanCompilerInvocation(const CompilerInvocation &Invocation, - const DependencyScanningService &Service) { +std::shared_ptr<CompilerInvocation> dependencies::createScanCompilerInvocation( + const CompilerInvocation &Invocation, + const DependencyScanningService &Service) { auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation); sanitizeDiagOpts(ScanInvocation->getDiagnosticOpts()); @@ -508,10 +509,9 @@ dependencies::computePrebuiltModulesASTMap( return PrebuiltModulesASTMap; } -/// Creates dependency output options to be reported to the dependency consumer, -/// deducing missing information if necessary. -static std::unique_ptr<DependencyOutputOptions> -createDependencyOutputOptions(const CompilerInvocation &Invocation) { +std::unique_ptr<DependencyOutputOptions> +dependencies::createDependencyOutputOptions( + const CompilerInvocation &Invocation) { auto Opts = std::make_unique<DependencyOutputOptions>( Invocation.getDependencyOutputOpts()); // We need at least one -MT equivalent for the generator of make dependency >From 50e6fa6b7c6ba6e62a5544fdfd77157d16e5cbdc Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Tue, 3 Mar 2026 08:16:51 -0800 Subject: [PATCH 3/4] Lift by-name Tool APIs to new type --- .../DependencyScannerImpl.h | 40 ---- .../DependencyScanningWorker.h | 7 +- .../clang/Tooling/DependencyScanningTool.h | 141 ++++++++---- .../DependencyScannerImpl.cpp | 153 ------------- clang/lib/Tooling/DependencyScanningTool.cpp | 213 +++++++++++++++--- clang/tools/clang-scan-deps/ClangScanDeps.cpp | 8 +- 6 files changed, 289 insertions(+), 273 deletions(-) diff --git a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h index 716d69f19347c..24cf1afaaa450 100644 --- a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h +++ b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h @@ -128,46 +128,6 @@ std::shared_ptr<ModuleDepCollector> initializeScanInstanceDependencyCollector( DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, llvm::SmallVector<StringRef> &StableDirs); - -class CompilerInstanceWithContext { - // Context - DependencyScanningWorker &Worker; - llvm::StringRef CWD; - std::vector<std::string> CommandLine; - - // Context - Diagnostics engine. - DiagnosticConsumer *DiagConsumer = nullptr; - std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts; - - // Context - compiler invocation - std::unique_ptr<CompilerInvocation> OriginalInvocation; - - // Context - output options - std::unique_ptr<DependencyOutputOptions> OutputOpts; - - // Context - stable directory handling - llvm::SmallVector<StringRef> StableDirs; - PrebuiltModulesAttrsMap PrebuiltModuleASTMap; - - // Compiler Instance - std::unique_ptr<CompilerInstance> CIPtr; - - // Source location offset. - int32_t SrcLocOffset = 0; - -public: - CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD, - const std::vector<std::string> &CMD) - : Worker(Worker), CWD(CWD), CommandLine(CMD) {}; - - // The two methods below returns false when they fail, with the detail - // accumulated in \c DiagEngineWithDiagOpts's diagnostic consumer. - bool initialize( - std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, - IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS); - bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer, - DependencyActionController &Controller); -}; } // namespace dependencies } // namespace clang diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h index 5506d9f78d9fc..0a5c4936f7fe7 100644 --- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h @@ -27,10 +27,13 @@ namespace clang { class DependencyOutputOptions; +namespace tooling { +class CompilerInstanceWithContext; +} + namespace dependencies { class DependencyScanningWorkerFilesystem; -class CompilerInstanceWithContext; /// A command-line tool invocation that is part of building a TU. /// @@ -135,7 +138,7 @@ class DependencyScanningWorker { /// overlaid on top of the base VFS passed in the constructor. IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; - friend CompilerInstanceWithContext; + friend tooling::CompilerInstanceWithContext; }; std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>, diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h index 694c1cb2a1f72..f0aa7615f0844 100644 --- a/clang/include/clang/Tooling/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanningTool.h @@ -111,10 +111,90 @@ class DependencyScanningTool { const llvm::DenseSet<dependencies::ModuleID> &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput); - /// The following two methods provide a new interface to perform - /// by name dependency scan. The new interface's intention is to improve - /// dependency scanning performance when a sequence of name is looked up - /// with the same current working directory and the command line. + llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); } + +private: + dependencies::DependencyScanningWorker Worker; + + friend class CompilerInstanceWithContext; +}; + +/// Run the dependency scanning worker for the given driver or frontend +/// command-line, and report the discovered dependencies to the provided +/// consumer. +/// +/// OverlayFS should be based on the Worker's dependency scanning file-system +/// and can be used to provide any input specified on the command-line as +/// in-memory file. If no overlay file-system is provided, the Worker's +/// dependency scanning file-system is used instead. +/// +/// \returns false if any errors occurred (with diagnostics reported to +/// \c DiagConsumer), true otherwise. +bool computeDependencies( + dependencies::DependencyScanningWorker &Worker, StringRef WorkingDirectory, + ArrayRef<std::string> CommandLine, + dependencies::DependencyConsumer &Consumer, + dependencies::DependencyActionController &Controller, + DiagnosticConsumer &DiagConsumer, + llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS = nullptr); + +class CompilerInstanceWithContext { + // Context + dependencies::DependencyScanningWorker &Worker; + llvm::StringRef CWD; + std::vector<std::string> CommandLine; + + // Context - Diagnostics engine. + DiagnosticConsumer *DiagConsumer = nullptr; + std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts> + DiagEngineWithCmdAndOpts; + std::unique_ptr<dependencies::TextDiagnosticsPrinterWithOutput> + DiagPrinterWithOS; + + // Context - compiler invocation + std::unique_ptr<CompilerInvocation> OriginalInvocation; + + // Context - output options + std::unique_ptr<DependencyOutputOptions> OutputOpts; + + // Context - stable directory handling + llvm::SmallVector<StringRef> StableDirs; + dependencies::PrebuiltModulesAttrsMap PrebuiltModuleASTMap; + + // Compiler Instance + std::unique_ptr<CompilerInstance> CIPtr; + + // Source location offset. + int32_t SrcLocOffset = 0; + + CompilerInstanceWithContext(dependencies::DependencyScanningWorker &Worker, + StringRef CWD, ArrayRef<std::string> CommandLine) + : Worker(Worker), CWD(CWD), CommandLine(std::move(CommandLine)) {}; + + CompilerInstanceWithContext(dependencies::DependencyScanningWorker &Worker) + : Worker(Worker) {}; + + // The two methods below returns false when they fail, with the detail + // accumulated in \c DiagEngineWithDiagOpts's diagnostic consumer. + bool initialize(std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts> + DiagEngineWithDiagOpts, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS); + +public: + /// @brief Initialize the tool's compiler instance from the commandline. + /// The compiler instance only takes a `-cc1` job, so this method + /// builds the `-cc1` job from the CommandLine input. + /// @param Tool The dependency scanning tool whose compiler instance + /// with context is initialized. + /// @param CWD The current working directory. + /// @param CommandLine This command line may be a driver command or a cc1 + /// command. + /// @param DC A diagnostics consumer to report error if the initialization + /// fails. + static std::optional<CompilerInstanceWithContext> + initializeFromCommandline(DependencyScanningTool &Tool, StringRef CWD, + ArrayRef<std::string> CommandLine, + DiagnosticConsumer &DC); /// @brief Initializing the context and the compiler instance. /// This method must be called before calling @@ -122,8 +202,14 @@ class DependencyScanningTool { /// @param CWD The current working directory used during the scan. /// @param CommandLine The commandline used for the scan. /// @return Error if the initializaiton fails. - llvm::Error initializeCompilerInstanceWithContextOrError( - StringRef CWD, ArrayRef<std::string> CommandLine); + static llvm::Expected<CompilerInstanceWithContext> + initializeOrError(DependencyScanningTool &Tool, StringRef CWD, + ArrayRef<std::string> CommandLine); + + bool + computeDependencies(StringRef ModuleName, + dependencies::DependencyConsumer &Consumer, + dependencies::DependencyActionController &Controller); /// @brief Computes the dependeny for the module named ModuleName. /// @param ModuleName The name of the module for which this method computes @@ -140,53 +226,12 @@ class DependencyScanningTool { /// @return An instance of \c TranslationUnitDeps if the scan is successful. /// Otherwise it returns an error. llvm::Expected<dependencies::TranslationUnitDeps> - computeDependenciesByNameWithContextOrError( + computeDependenciesByNameOrError( StringRef ModuleName, const llvm::DenseSet<dependencies::ModuleID> &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput); - - llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); } - - /// @brief Initialize the tool's compiler instance from the commandline. - /// The compiler instance only takes a `-cc1` job, so this method - /// builds the `-cc1` job from the CommandLine input. - /// @param Tool The dependency scanning tool whose compiler instance - /// with context is initialized. - /// @param CWD The current working directory. - /// @param CommandLine This command line may be a driver command or a cc1 - /// command. - /// @param DC A diagnostics consumer to report error if the initialization - /// fails. - static bool initializeWorkerCIWithContextFromCommandline( - DependencyScanningTool &Tool, StringRef CWD, - ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC); - -private: - dependencies::DependencyScanningWorker Worker; - std::unique_ptr<dependencies::TextDiagnosticsPrinterWithOutput> - DiagPrinterWithOS; - std::unique_ptr<dependencies::CompilerInstanceWithContext> CIWithContext; }; -/// Run the dependency scanning worker for the given driver or frontend -/// command-line, and report the discovered dependencies to the provided -/// consumer. -/// -/// OverlayFS should be based on the Worker's dependency scanning file-system -/// and can be used to provide any input specified on the command-line as -/// in-memory file. If no overlay file-system is provided, the Worker's -/// dependency scanning file-system is used instead. -/// -/// \returns false if any errors occurred (with diagnostics reported to -/// \c DiagConsumer), true otherwise. -bool computeDependencies( - dependencies::DependencyScanningWorker &Worker, StringRef WorkingDirectory, - ArrayRef<std::string> CommandLine, - dependencies::DependencyConsumer &Consumer, - dependencies::DependencyActionController &Controller, - DiagnosticConsumer &DiagConsumer, - llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS = nullptr); - } // end namespace tooling } // end namespace clang diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp index 9aeae580711f7..0e345af8817ae 100644 --- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp @@ -805,156 +805,3 @@ bool DependencyScanningAction::runInvocation( return Result; } - -bool CompilerInstanceWithContext::initialize( - std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, - IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS) { - assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!"); - DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts); - DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient(); - -#ifndef NDEBUG - assert(OverlayFS && "OverlayFS required!"); - bool SawDepFS = false; - OverlayFS->visit([&](llvm::vfs::FileSystem &VFS) { - SawDepFS |= &VFS == Worker.DepFS.get(); - }); - assert(SawDepFS && "OverlayFS not based on DepFS"); -#endif - - OriginalInvocation = createCompilerInvocation( - CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine); - if (!OriginalInvocation) { - DiagEngineWithCmdAndOpts->DiagEngine->Report( - diag::err_fe_expected_compiler_job) - << llvm::join(CommandLine, " "); - return false; - } - - if (any(Worker.Service.getOpts().OptimizeArgs & - ScanningOptimizations::Macros)) - canonicalizeDefines(OriginalInvocation->getPreprocessorOpts()); - - // Create the CompilerInstance. - std::shared_ptr<ModuleCache> ModCache = - makeInProcessModuleCache(Worker.Service.getModuleCacheEntries()); - CIPtr = std::make_unique<CompilerInstance>( - createScanCompilerInvocation(*OriginalInvocation, Worker.Service), - Worker.PCHContainerOps, std::move(ModCache)); - auto &CI = *CIPtr; - - initializeScanCompilerInstance( - CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), - Worker.Service, Worker.DepFS); - - StableDirs = getInitialStableDirs(CI); - auto MaybePrebuiltModulesASTMap = - computePrebuiltModulesASTMap(CI, StableDirs); - if (!MaybePrebuiltModulesASTMap) - return false; - - PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap); - OutputOpts = createDependencyOutputOptions(*OriginalInvocation); - - // We do not create the target in initializeScanCompilerInstance because - // setting it here is unique for by-name lookups. We create the target only - // once here, and the information is reused for all computeDependencies calls. - // We do not need to call createTarget explicitly if we go through - // CompilerInstance::ExecuteAction to perform scanning. - CI.createTarget(); - - return true; -} - -bool CompilerInstanceWithContext::computeDependencies( - StringRef ModuleName, DependencyConsumer &Consumer, - DependencyActionController &Controller) { - assert(CIPtr && "CIPtr must be initialized before calling this method"); - auto &CI = *CIPtr; - - // We need to reset the diagnostics, so that the diagnostics issued - // during a previous computeDependencies call do not affect the current call. - // If we do not reset, we may inherit fatal errors from a previous call. - CI.getDiagnostics().Reset(); - - // We create this cleanup object because computeDependencies may exit - // early with errors. - llvm::scope_exit CleanUp([&]() { - CI.clearDependencyCollectors(); - // The preprocessor may not be created at the entry of this method, - // but it must have been created when this method returns, whether - // there are errors during scanning or not. - CI.getPreprocessor().removePPCallbacks(); - }); - - auto MDC = initializeScanInstanceDependencyCollector( - CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer, - Worker.Service, - /* The MDC's constructor makes a copy of the OriginalInvocation, so - we can pass it in without worrying that it might be changed across - invocations of computeDependencies. */ - *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs); - - if (!SrcLocOffset) { - // When SrcLocOffset is zero, we are at the beginning of the fake source - // file. In this case, we call BeginSourceFile to initialize. - std::unique_ptr<FrontendAction> Action = - std::make_unique<PreprocessOnlyAction>(); - auto *InputFile = CI.getFrontendOpts().Inputs.begin(); - bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile); - assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed"); - (void)ActionBeginSucceeded; - } - - Preprocessor &PP = CI.getPreprocessor(); - SourceManager &SM = PP.getSourceManager(); - FileID MainFileID = SM.getMainFileID(); - SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID); - SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset); - PPCallbacks *CB = nullptr; - if (!SrcLocOffset) { - // We need to call EnterSourceFile when SrcLocOffset is zero to initialize - // the preprocessor. - bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation()); - assert(!PPFailed && "Preprocess must be able to enter the main file."); - (void)PPFailed; - CB = MDC->getPPCallbacks(); - } else { - // When SrcLocOffset is non-zero, the preprocessor has already been - // initialized through a previous call of computeDependencies. We want to - // preserve the PP's state, hence we do not call EnterSourceFile again. - MDC->attachToPreprocessor(PP); - CB = MDC->getPPCallbacks(); - - FileID PrevFID; - SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation); - CB->LexedFileChanged(MainFileID, - PPChainedCallbacks::LexedFileChangeReason::EnterFile, - FileType, PrevFID, IDLocation); - } - - // FIXME: Scan modules asynchronously here as well. - - SrcLocOffset++; - SmallVector<IdentifierLoc, 2> Path; - IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); - Path.emplace_back(IDLocation, ModuleID); - auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false); - - assert(CB && "Must have PPCallbacks after module loading"); - CB->moduleImport(SourceLocation(), Path, ModResult); - // Note that we are calling the CB's EndOfMainFile function, which - // forwards the results to the dependency consumer. - // It does not indicate the end of processing the fake file. - CB->EndOfMainFile(); - - if (!ModResult) - return false; - - CompilerInvocation ModuleInvocation(*OriginalInvocation); - MDC->applyDiscoveredDependencies(ModuleInvocation); - Consumer.handleBuildCommand( - {CommandLine[0], ModuleInvocation.getCC1CommandLine()}); - - return true; -} diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index 79a84f0148fcf..5caa1fcef9d1a 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -11,7 +11,10 @@ #include "clang/Basic/DiagnosticFrontend.h" #include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/Driver/Tool.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/Utils.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/iterator.h" #include "llvm/TargetParser/Host.h" @@ -282,12 +285,13 @@ DependencyScanningTool::getModuleDependencies( StringRef ModuleName, ArrayRef<std::string> CommandLine, StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { - if (auto Error = - initializeCompilerInstanceWithContextOrError(CWD, CommandLine)) + auto MaybeCIWithContext = + CompilerInstanceWithContext::initializeOrError(*this, CWD, CommandLine); + if (auto Error = MaybeCIWithContext.takeError()) return Error; - return computeDependenciesByNameWithContextOrError(ModuleName, AlreadySeen, - LookupModuleOutput); + return MaybeCIWithContext->computeDependenciesByNameOrError( + ModuleName, AlreadySeen, LookupModuleOutput); } static std::optional<SmallVector<std::string, 0>> getFirstCC1CommandLine( @@ -312,7 +316,8 @@ static std::optional<SmallVector<std::string, 0>> getFirstCC1CommandLine( return std::nullopt; } -bool DependencyScanningTool::initializeWorkerCIWithContextFromCommandline( +std::optional<CompilerInstanceWithContext> +CompilerInstanceWithContext::initializeFromCommandline( DependencyScanningTool &Tool, StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) { auto [OverlayFS, ModifiedCommandLine] = initVFSForByNameScanning( @@ -324,10 +329,11 @@ bool DependencyScanningTool::initializeWorkerCIWithContextFromCommandline( if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") { // The input command line is already a -cc1 invocation; initialize the // compiler instance directly from it. - Tool.CIWithContext = std::make_unique<CompilerInstanceWithContext>( - Tool.Worker, CWD, CommandLine); - return Tool.CIWithContext->initialize(std::move(DiagEngineWithCmdAndOpts), - OverlayFS); + CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, CommandLine); + if (!CIWithContext.initialize(std::move(DiagEngineWithCmdAndOpts), + OverlayFS)) + return std::nullopt; + return CIWithContext; } // The input command line is either a driver-style command line, or @@ -336,32 +342,35 @@ bool DependencyScanningTool::initializeWorkerCIWithContextFromCommandline( const auto MaybeFirstCC1 = getFirstCC1CommandLine( ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS); if (!MaybeFirstCC1) - return false; + return std::nullopt; std::vector<std::string> CC1CommandLine(MaybeFirstCC1->begin(), MaybeFirstCC1->end()); - Tool.CIWithContext = std::make_unique<CompilerInstanceWithContext>( - Tool.Worker, CWD, std::move(CC1CommandLine)); - return Tool.CIWithContext->initialize(std::move(DiagEngineWithCmdAndOpts), - OverlayFS); + CompilerInstanceWithContext CIWithContext(Tool.Worker, CWD, + std::move(CC1CommandLine)); + if (!CIWithContext.initialize(std::move(DiagEngineWithCmdAndOpts), OverlayFS)) + return std::nullopt; + return CIWithContext; } -llvm::Error -DependencyScanningTool::initializeCompilerInstanceWithContextOrError( - StringRef CWD, ArrayRef<std::string> CommandLine) { - DiagPrinterWithOS = +llvm::Expected<CompilerInstanceWithContext> +CompilerInstanceWithContext::initializeOrError( + DependencyScanningTool &Tool, StringRef CWD, + ArrayRef<std::string> CommandLine) { + auto DiagPrinterWithOS = std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine); - bool Result = initializeWorkerCIWithContextFromCommandline( - *this, CWD, CommandLine, DiagPrinterWithOS->DiagPrinter); - - if (Result) - return llvm::Error::success(); + auto Result = initializeFromCommandline(Tool, CWD, CommandLine, + DiagPrinterWithOS->DiagPrinter); + if (Result) { + Result->DiagPrinterWithOS = std::move(DiagPrinterWithOS); + return std::move(*Result); + } return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } llvm::Expected<TranslationUnitDeps> -DependencyScanningTool::computeDependenciesByNameWithContextOrError( +CompilerInstanceWithContext::computeDependenciesByNameOrError( StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { FullDependencyConsumer Consumer(AlreadySeen); @@ -369,8 +378,160 @@ DependencyScanningTool::computeDependenciesByNameWithContextOrError( // We need to clear the DiagnosticOutput so that each by-name lookup // has a clean diagnostics buffer. DiagPrinterWithOS->DiagnosticOutput.clear(); - assert(CIWithContext && "CompilerInstance with context required!"); - if (CIWithContext->computeDependencies(ModuleName, Consumer, Controller)) + if (computeDependencies(ModuleName, Consumer, Controller)) return Consumer.takeTranslationUnitDeps(); return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } + +bool CompilerInstanceWithContext::initialize( + std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS) { + assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!"); + DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts); + DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient(); + +#ifndef NDEBUG + assert(OverlayFS && "OverlayFS required!"); + bool SawDepFS = false; + OverlayFS->visit([&](llvm::vfs::FileSystem &VFS) { + SawDepFS |= &VFS == Worker.DepFS.get(); + }); + assert(SawDepFS && "OverlayFS not based on DepFS"); +#endif + + OriginalInvocation = createCompilerInvocation( + CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine); + if (!OriginalInvocation) { + DiagEngineWithCmdAndOpts->DiagEngine->Report( + diag::err_fe_expected_compiler_job) + << llvm::join(CommandLine, " "); + return false; + } + + if (any(Worker.Service.getOpts().OptimizeArgs & + ScanningOptimizations::Macros)) + canonicalizeDefines(OriginalInvocation->getPreprocessorOpts()); + + // Create the CompilerInstance. + std::shared_ptr<ModuleCache> ModCache = + makeInProcessModuleCache(Worker.Service.getModuleCacheEntries()); + CIPtr = std::make_unique<CompilerInstance>( + createScanCompilerInvocation(*OriginalInvocation, Worker.Service), + Worker.PCHContainerOps, std::move(ModCache)); + auto &CI = *CIPtr; + + initializeScanCompilerInstance( + CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), + Worker.Service, Worker.DepFS); + + StableDirs = getInitialStableDirs(CI); + auto MaybePrebuiltModulesASTMap = + computePrebuiltModulesASTMap(CI, StableDirs); + if (!MaybePrebuiltModulesASTMap) + return false; + + PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap); + OutputOpts = createDependencyOutputOptions(*OriginalInvocation); + + // We do not create the target in initializeScanCompilerInstance because + // setting it here is unique for by-name lookups. We create the target only + // once here, and the information is reused for all computeDependencies calls. + // We do not need to call createTarget explicitly if we go through + // CompilerInstance::ExecuteAction to perform scanning. + CI.createTarget(); + + return true; +} + +bool CompilerInstanceWithContext::computeDependencies( + StringRef ModuleName, DependencyConsumer &Consumer, + DependencyActionController &Controller) { + assert(CIPtr && "CIPtr must be initialized before calling this method"); + auto &CI = *CIPtr; + + // We need to reset the diagnostics, so that the diagnostics issued + // during a previous computeDependencies call do not affect the current call. + // If we do not reset, we may inherit fatal errors from a previous call. + CI.getDiagnostics().Reset(); + + // We create this cleanup object because computeDependencies may exit + // early with errors. + llvm::scope_exit CleanUp([&]() { + CI.clearDependencyCollectors(); + // The preprocessor may not be created at the entry of this method, + // but it must have been created when this method returns, whether + // there are errors during scanning or not. + CI.getPreprocessor().removePPCallbacks(); + }); + + auto MDC = initializeScanInstanceDependencyCollector( + CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer, + Worker.Service, + /* The MDC's constructor makes a copy of the OriginalInvocation, so + we can pass it in without worrying that it might be changed across + invocations of computeDependencies. */ + *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs); + + if (!SrcLocOffset) { + // When SrcLocOffset is zero, we are at the beginning of the fake source + // file. In this case, we call BeginSourceFile to initialize. + std::unique_ptr<FrontendAction> Action = + std::make_unique<PreprocessOnlyAction>(); + auto *InputFile = CI.getFrontendOpts().Inputs.begin(); + bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile); + assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed"); + (void)ActionBeginSucceeded; + } + + Preprocessor &PP = CI.getPreprocessor(); + SourceManager &SM = PP.getSourceManager(); + FileID MainFileID = SM.getMainFileID(); + SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID); + SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset); + PPCallbacks *CB = nullptr; + if (!SrcLocOffset) { + // We need to call EnterSourceFile when SrcLocOffset is zero to initialize + // the preprocessor. + bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation()); + assert(!PPFailed && "Preprocess must be able to enter the main file."); + (void)PPFailed; + CB = MDC->getPPCallbacks(); + } else { + // When SrcLocOffset is non-zero, the preprocessor has already been + // initialized through a previous call of computeDependencies. We want to + // preserve the PP's state, hence we do not call EnterSourceFile again. + MDC->attachToPreprocessor(PP); + CB = MDC->getPPCallbacks(); + + FileID PrevFID; + SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation); + CB->LexedFileChanged(MainFileID, + PPChainedCallbacks::LexedFileChangeReason::EnterFile, + FileType, PrevFID, IDLocation); + } + + // FIXME: Scan modules asynchronously here as well. + + SrcLocOffset++; + SmallVector<IdentifierLoc, 2> Path; + IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); + Path.emplace_back(IDLocation, ModuleID); + auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false); + + assert(CB && "Must have PPCallbacks after module loading"); + CB->moduleImport(SourceLocation(), Path, ModResult); + // Note that we are calling the CB's EndOfMainFile function, which + // forwards the results to the dependency consumer. + // It does not indicate the end of processing the fake file. + CB->EndOfMainFile(); + + if (!ModResult) + return false; + + CompilerInvocation ModuleInvocation(*OriginalInvocation); + MDC->applyDiscoveredDependencies(ModuleInvocation); + Consumer.handleBuildCommand( + {CommandLine[0], ModuleInvocation.getCC1CommandLine()}); + + return true; +} diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index eb3de3319bc00..737360f9266e6 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -1071,9 +1071,9 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { LocalIndex, DependencyOS, Errs)) HadErrors = true; } else { - if (llvm::Error Err = - WorkerTool.initializeCompilerInstanceWithContextOrError( - CWD, Input->CommandLine)) { + auto CIWithCtx = CompilerInstanceWithContext::initializeOrError( + WorkerTool, CWD, Input->CommandLine); + if (llvm::Error Err = CIWithCtx.takeError()) { handleErrorWithInfoString( "Compiler instance with context setup error", std::move(Err), DependencyOS, Errs); @@ -1083,7 +1083,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { for (auto N : Names) { auto MaybeModuleDepsGraph = - WorkerTool.computeDependenciesByNameWithContextOrError( + CIWithCtx->computeDependenciesByNameOrError( N, AlreadySeenModules, LookupOutput); if (handleModuleResult(N, MaybeModuleDepsGraph, *FD, LocalIndex, DependencyOS, Errs)) { >From 2fc0c460d5bf111550932dc98dc700b4a746e0c1 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Thu, 5 Mar 2026 08:12:13 -0800 Subject: [PATCH 4/4] Remove extra constructor, revert extra change --- clang/include/clang/Tooling/DependencyScanningTool.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h index f0aa7615f0844..40e791fd5bff5 100644 --- a/clang/include/clang/Tooling/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanningTool.h @@ -168,14 +168,10 @@ class CompilerInstanceWithContext { int32_t SrcLocOffset = 0; CompilerInstanceWithContext(dependencies::DependencyScanningWorker &Worker, - StringRef CWD, ArrayRef<std::string> CommandLine) - : Worker(Worker), CWD(CWD), CommandLine(std::move(CommandLine)) {}; + StringRef CWD, + const std::vector<std::string> &CMD) + : Worker(Worker), CWD(CWD), CommandLine(CMD) {}; - CompilerInstanceWithContext(dependencies::DependencyScanningWorker &Worker) - : Worker(Worker) {}; - - // The two methods below returns false when they fail, with the detail - // accumulated in \c DiagEngineWithDiagOpts's diagnostic consumer. bool initialize(std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
