[Lldb-commits] [clang] [clang-tools-extra] [flang] [lldb] [llvm] Reapply "[clang] Refactor to remove clangDriver dependency from clangFrontend and flangFrontend (#165277)" (PR #169599)

Naveen Seth Hanig via lldb-commits lldb-commits at lists.llvm.org
Tue Nov 25 19:58:15 PST 2025


https://github.com/naveen-seth updated https://github.com/llvm/llvm-project/pull/169599

>From 5aa59dd94a10cb5e8d8500758c79efb111b3054c Mon Sep 17 00:00:00 2001
From: Naveen Seth Hanig <naveen.hanig at outlook.com>
Date: Wed, 26 Nov 2025 03:31:28 +0100
Subject: [PATCH 1/2] Reapply "[clang] Refactor to remove clangDriver
 dependency from clangFrontend  and flangFrontend (#165277)"

This relands #165277 by reverting #169397.
This also relands the corresponding bazel port by reverting #169410.

The original revert was due to a report of a broken build, which was later resolved by fully clearing the build directory.
---
 clang-tools-extra/clangd/CompileCommands.cpp  |   3 +-
 clang-tools-extra/clangd/Compiler.cpp         |   1 +
 clang/docs/ReleaseNotes.rst                   |   2 +
 clang/include/clang/Driver/CommonArgs.h       |  10 -
 .../clang/Driver/CreateASTUnitFromArgs.h      |  80 ++++
 .../clang/Driver/CreateInvocationFromArgs.h   |  76 ++++
 clang/include/clang/Driver/Driver.h           |   4 -
 clang/include/clang/Frontend/ASTUnit.h        | 144 ++++----
 .../clang/Frontend/CompilerInvocation.h       |  10 -
 .../clang/Frontend/StandaloneDiagnostic.h     |  82 +++++
 clang/include/clang/Frontend/Utils.h          |  45 ---
 clang/include/clang/Options/OptionUtils.h     |  24 ++
 clang/lib/CrossTU/CMakeLists.txt              |   1 +
 clang/lib/CrossTU/CrossTranslationUnit.cpp    |   3 +-
 clang/lib/Driver/CMakeLists.txt               |   4 +
 clang/lib/Driver/CreateASTUnitFromArgs.cpp    | 166 +++++++++
 .../CreateInvocationFromArgs.cpp}             |  13 +-
 clang/lib/Driver/Driver.cpp                   |  35 +-
 clang/lib/Driver/ToolChains/Clang.cpp         |   1 +
 clang/lib/Driver/ToolChains/CommonArgs.cpp    | 163 ---------
 clang/lib/Driver/ToolChains/Flang.cpp         |   1 +
 clang/lib/Frontend/ASTUnit.cpp                | 343 +++---------------
 clang/lib/Frontend/CMakeLists.txt             |   3 +-
 clang/lib/Frontend/CompilerInvocation.cpp     |   8 -
 clang/lib/Frontend/StandaloneDiagnostic.cpp   | 117 ++++++
 clang/lib/Interpreter/CMakeLists.txt          |   1 +
 clang/lib/Interpreter/Interpreter.cpp         |   3 +-
 clang/lib/Options/OptionUtils.cpp             | 215 ++++++++++-
 clang/lib/Tooling/Tooling.cpp                 |   4 +-
 clang/tools/c-index-test/CMakeLists.txt       |   1 +
 clang/tools/c-index-test/core_main.cpp        |   1 +
 clang/tools/diagtool/CMakeLists.txt           |   1 +
 clang/tools/diagtool/ShowEnabledWarnings.cpp  |   1 +
 clang/tools/driver/cc1_main.cpp               |   3 +-
 clang/tools/libclang/CIndex.cpp               |   3 +-
 clang/tools/libclang/CIndexer.cpp             |   3 +-
 clang/tools/libclang/CMakeLists.txt           |   1 +
 clang/tools/libclang/Indexing.cpp             |   1 +
 clang/unittests/Driver/DXCModeTest.cpp        |   1 +
 clang/unittests/Driver/ToolChainTest.cpp      |   1 +
 clang/unittests/Frontend/ASTUnitTest.cpp      |   6 +-
 .../Frontend/CompilerInstanceTest.cpp         |   1 +
 clang/unittests/Frontend/UtilsTest.cpp        |   1 +
 clang/unittests/Sema/CMakeLists.txt           |   1 +
 clang/unittests/Sema/SemaNoloadLookupTest.cpp |   1 +
 .../Serialization/ForceCheckFileInputTest.cpp |   1 +
 .../Serialization/LoadSpecLazilyTest.cpp      |   1 +
 .../Serialization/ModuleCacheTest.cpp         |   1 +
 .../Serialization/NoCommentsTest.cpp          |   1 +
 .../PreambleInNamedModulesTest.cpp            |   1 +
 .../Serialization/VarDeclConstantInitTest.cpp |   1 +
 clang/unittests/Tooling/Syntax/TokensTest.cpp |   1 +
 .../unittests/Tooling/Syntax/TreeTestBase.cpp |   1 +
 flang/lib/Frontend/CMakeLists.txt             |   1 -
 flang/lib/Frontend/CompilerInvocation.cpp     |   5 +-
 lldb/source/Commands/CommandObjectTarget.cpp  |   1 +
 .../ExpressionParser/Clang/CMakeLists.txt     |   2 +-
 .../ExpressionParser/Clang/ClangHost.cpp      |   4 +-
 .../Clang/ClangModulesDeclVendor.cpp          |   1 +
 lldb/unittests/Expression/ClangParserTest.cpp |   4 +-
 .../llvm-project-overlay/clang/BUILD.bazel    |   2 +-
 61 files changed, 935 insertions(+), 682 deletions(-)
 create mode 100644 clang/include/clang/Driver/CreateASTUnitFromArgs.h
 create mode 100644 clang/include/clang/Driver/CreateInvocationFromArgs.h
 create mode 100644 clang/include/clang/Frontend/StandaloneDiagnostic.h
 create mode 100644 clang/lib/Driver/CreateASTUnitFromArgs.cpp
 rename clang/lib/{Frontend/CreateInvocationFromCommandLine.cpp => Driver/CreateInvocationFromArgs.cpp} (93%)
 create mode 100644 clang/lib/Frontend/StandaloneDiagnostic.cpp

diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp
index 7990f2719e9a0..4eda330716f21 100644
--- a/clang-tools-extra/clangd/CompileCommands.cpp
+++ b/clang-tools-extra/clangd/CompileCommands.cpp
@@ -132,8 +132,7 @@ std::optional<std::string> detectSysroot() {
 
 std::string detectStandardResourceDir() {
   static int StaticForMainAddr; // Just an address in this process.
-  return CompilerInvocation::GetResourcesPath("clangd",
-                                              (void *)&StaticForMainAddr);
+  return GetResourcesPath("clangd", (void *)&StaticForMainAddr);
 }
 
 // The path passed to argv[0] is important:
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 6ebc2eac25745..9ea7df139382a 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -9,6 +9,7 @@
 #include "Compiler.h"
 #include "support/Logger.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Serialization/PCHContainerOperations.h"
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c6a79ed71ca2f..c4d968bd01b65 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -84,6 +84,8 @@ Potentially Breaking Changes
 - Downstream projects that previously linked only against ``clangDriver`` may
   now (also) need to link against the new ``clangOptions`` library, since
   options-related code has been moved out of the Driver into a separate library.
+- The ``clangFrontend`` library no longer depends on ``clangDriver``, which may
+  break downstream projects that relied on this transitive dependency.
 
 C/C++ Language Potentially Breaking Changes
 -------------------------------------------
diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index ac17d6211d882..264bd4965f9ad 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -291,16 +291,6 @@ void handleVectorizeLoopsArgs(const llvm::opt::ArgList &Args,
 void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args,
                             llvm::opt::ArgStringList &CmdArgs);
 
-// Parse -mprefer-vector-width=. Return the Value string if well-formed.
-// Otherwise, return an empty string and issue a diagnosic message if needed.
-StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
-                                        const llvm::opt::ArgList &Args);
-
-// Parse -mrecip. Return the Value string if well-formed.
-// Otherwise, return an empty string and issue a diagnosic message if needed.
-StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags,
-                            const llvm::opt::ArgList &Args);
-
 // Convert ComplexRangeKind to a string that can be passed as a frontend option.
 std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range);
 
diff --git a/clang/include/clang/Driver/CreateASTUnitFromArgs.h b/clang/include/clang/Driver/CreateASTUnitFromArgs.h
new file mode 100644
index 0000000000000..30575cc04ca7c
--- /dev/null
+++ b/clang/include/clang/Driver/CreateASTUnitFromArgs.h
@@ -0,0 +1,80 @@
+//===-- CreateInvocationFromArgs.h - Create an ASTUnit from Args-*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for creating an ASTUnit from a vector of command line arguments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H
+#define LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H
+
+#include "clang/Frontend/ASTUnit.h"
+
+namespace clang {
+
+/// Create an ASTUnit from a vector of command line arguments, which must
+/// specify exactly one source file.
+///
+/// \param ArgBegin - The beginning of the argument vector.
+///
+/// \param ArgEnd - The end of the argument vector.
+///
+/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
+/// creating modules.
+///
+/// \param Diags - The diagnostics engine to use for reporting errors; its
+/// lifetime is expected to extend past that of the returned ASTUnit.
+///
+/// \param ResourceFilesPath - The path to the compiler resource files.
+///
+/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false,
+/// PCH are stored in temporary files.
+///
+/// \param PreambleStoragePath - The path to a directory, in which to create
+/// temporary PCH files. If empty, the default system temporary directory is
+/// used. This parameter is ignored if \p StorePreamblesInMemory is true.
+///
+/// \param ModuleFormat - If provided, uses the specific module format.
+///
+/// \param ErrAST - If non-null and parsing failed without any AST to return
+/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
+/// mainly to allow the caller to see the diagnostics.
+///
+/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses.
+/// Note that preamble is saved to a temporary directory on a RealFileSystem,
+/// so in order for it to be loaded correctly, VFS should have access to
+/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used
+/// if \p VFS is nullptr.
+///
+// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
+// shouldn't need to specify them at construction time.
+std::unique_ptr<ASTUnit> CreateASTUnitFromCommandLine(
+    const char **ArgBegin, const char **ArgEnd,
+    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
+    bool StorePreamblesInMemory = false,
+    StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false,
+    CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None,
+    ArrayRef<ASTUnit::RemappedFile> RemappedFiles = {},
+    bool RemappedFilesKeepOriginalName = true,
+    unsigned PrecompilePreambleAfterNParses = 0,
+    TranslationUnitKind TUKind = TU_Complete,
+    bool CacheCodeCompletionResults = false,
+    bool IncludeBriefCommentsInCodeCompletion = false,
+    bool AllowPCHWithCompilerErrors = false,
+    SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None,
+    bool SingleFileParse = false, bool UserFilesAreVolatile = false,
+    bool ForSerialization = false, bool RetainExcludedConditionalBlocks = false,
+    std::optional<StringRef> ModuleFormat = std::nullopt,
+    std::unique_ptr<ASTUnit> *ErrAST = nullptr,
+    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
+
+} // namespace clang
+
+#endif // LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H
diff --git a/clang/include/clang/Driver/CreateInvocationFromArgs.h b/clang/include/clang/Driver/CreateInvocationFromArgs.h
new file mode 100644
index 0000000000000..0e0f67373ce87
--- /dev/null
+++ b/clang/include/clang/Driver/CreateInvocationFromArgs.h
@@ -0,0 +1,76 @@
+//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for creating a CompilerInvocation from command-line arguments, for
+// tools to use in preparation to parse a file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H
+#define LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class CompilerInvocation;
+class DiagnosticsEngine;
+
+/// Optional inputs to createInvocation.
+struct CreateInvocationOptions {
+  /// Receives diagnostics encountered while parsing command-line flags.
+  /// If not provided, these are printed to stderr.
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags = nullptr;
+  /// Used e.g. to probe for system headers locations.
+  /// If not provided, the real filesystem is used.
+  /// FIXME: the driver does perform some non-virtualized IO.
+  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr;
+  /// Whether to attempt to produce a non-null (possibly incorrect) invocation
+  /// if any errors were encountered.
+  /// By default, always return null on errors.
+  bool RecoverOnError = false;
+  /// Allow the driver to probe the filesystem for PCH files.
+  /// This is used to replace -include with -include-pch in the cc1 args.
+  /// FIXME: ProbePrecompiled=true is a poor, historical default.
+  /// It misbehaves if the PCH file is from GCC, has the wrong version, etc.
+  bool ProbePrecompiled = false;
+  /// If set, the target is populated with the cc1 args produced by the driver.
+  /// This may be populated even if createInvocation returns nullptr.
+  std::vector<std::string> *CC1Args = nullptr;
+};
+
+/// Interpret clang arguments in preparation to parse a file.
+///
+/// This simulates a number of steps Clang takes when its driver is invoked:
+/// - choosing actions (e.g compile + link) to run
+/// - probing the system for settings like standard library locations
+/// - spawning a cc1 subprocess to compile code, with more explicit arguments
+/// - in the cc1 process, assembling those arguments into a CompilerInvocation
+///   which is used to configure the parser
+///
+/// This simulation is lossy, e.g. in some situations one driver run would
+/// result in multiple parses. (Multi-arch, CUDA, ...).
+/// This function tries to select a reasonable invocation that tools should use.
+///
+/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++".
+/// Absolute path is preferred - this affects searching for system headers.
+///
+/// May return nullptr if an invocation could not be determined.
+/// See CreateInvocationOptions::RecoverOnError to try harder!
+std::unique_ptr<CompilerInvocation>
+createInvocation(ArrayRef<const char *> Args,
+                 CreateInvocationOptions Opts = {});
+
+} // namespace clang
+
+#endif // LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index 83bcb7cab550f..76a6c5a128efb 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -406,10 +406,6 @@ class Driver {
                               SmallString<128> &CrashDiagDir);
 
 public:
-  /// Takes the path to a binary that's either in bin/ or lib/ and returns
-  /// the path to clang's resource directory.
-  static std::string GetResourcesPath(StringRef BinaryPath);
-
   Driver(StringRef ClangExecutable, StringRef TargetTriple,
          DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler",
          IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h
index e585933a5c8be..341460e1962cb 100644
--- a/clang/include/clang/Frontend/ASTUnit.h
+++ b/clang/include/clang/Frontend/ASTUnit.h
@@ -23,11 +23,13 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetOptions.h"
 #include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/Frontend/StandaloneDiagnostic.h"
 #include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/ModuleLoader.h"
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Serialization/ASTWriter.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -36,6 +38,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/iterator_range.h"
+#include "llvm/Bitstream/BitstreamWriter.h"
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
@@ -88,25 +91,6 @@ enum class CaptureDiagsKind { None, All, AllWithoutNonErrorsFromIncludes };
 
 /// Utility class for loading a ASTContext from an AST file.
 class ASTUnit {
-public:
-  struct StandaloneFixIt {
-    std::pair<unsigned, unsigned> RemoveRange;
-    std::pair<unsigned, unsigned> InsertFromRange;
-    std::string CodeToInsert;
-    bool BeforePreviousInsertions;
-  };
-
-  struct StandaloneDiagnostic {
-    unsigned ID;
-    DiagnosticsEngine::Level Level;
-    std::string Message;
-    std::string Filename;
-    unsigned LocOffset;
-    std::vector<std::pair<unsigned, unsigned>> Ranges;
-    std::vector<StandaloneFixIt> FixIts;
-  };
-
-private:
   std::unique_ptr<LangOptions> LangOpts;
   std::unique_ptr<CodeGenOptions> CodeGenOpts;
   // FIXME: The documentation on \c LoadFrom* member functions states that the
@@ -129,7 +113,15 @@ class ASTUnit {
   bool HadModuleLoaderFatalFailure = false;
   bool StorePreamblesInMemory = false;
 
-  struct ASTWriterData;
+  /// Utility struct for managing ASTWriter and its associated data streams.
+  struct ASTWriterData {
+    SmallString<128> Buffer;
+    llvm::BitstreamWriter Stream;
+    ASTWriter Writer;
+
+    ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts)
+        : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {}
+  };
   std::unique_ptr<ASTWriterData> WriterData;
 
   FileSystemOptions FileSystemOpts;
@@ -271,11 +263,6 @@ class ASTUnit {
   static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
                              ASTUnit &AST, CaptureDiagsKind CaptureDiagnostics);
 
-  void
-  TranslateStoredDiagnostics(FileManager &FileMgr, SourceManager &SrcMan,
-                             const SmallVectorImpl<StandaloneDiagnostic> &Diags,
-                             SmallVectorImpl<StoredDiagnostic> &Out);
-
   void clearFileLevelDecls();
 
 public:
@@ -834,65 +821,24 @@ class ASTUnit {
       bool IncludeBriefCommentsInCodeCompletion = false,
       bool UserFilesAreVolatile = false);
 
-  /// LoadFromCommandLine - Create an ASTUnit from a vector of command line
-  /// arguments, which must specify exactly one source file.
-  ///
-  /// \param ArgBegin - The beginning of the argument vector.
-  ///
-  /// \param ArgEnd - The end of the argument vector.
-  ///
-  /// \param PCHContainerOps - The PCHContainerOperations to use for loading and
-  /// creating modules.
-  ///
-  /// \param Diags - The diagnostics engine to use for reporting errors; its
-  /// lifetime is expected to extend past that of the returned ASTUnit.
-  ///
-  /// \param ResourceFilesPath - The path to the compiler resource files.
-  ///
-  /// \param StorePreamblesInMemory - Whether to store PCH in memory. If false,
-  /// PCH are stored in temporary files.
-  ///
-  /// \param PreambleStoragePath - The path to a directory, in which to create
-  /// temporary PCH files. If empty, the default system temporary directory is
-  /// used. This parameter is ignored if \p StorePreamblesInMemory is true.
-  ///
-  /// \param ModuleFormat - If provided, uses the specific module format.
-  ///
-  /// \param ErrAST - If non-null and parsing failed without any AST to return
-  /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
-  /// mainly to allow the caller to see the diagnostics.
-  ///
-  /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses.
-  /// Note that preamble is saved to a temporary directory on a RealFileSystem,
-  /// so in order for it to be loaded correctly, VFS should have access to
-  /// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used
-  /// if \p VFS is nullptr.
-  ///
-  // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
-  // shouldn't need to specify them at construction time.
-  static std::unique_ptr<ASTUnit> LoadFromCommandLine(
+  friend std::unique_ptr<ASTUnit> CreateASTUnitFromCommandLine(
       const char **ArgBegin, const char **ArgEnd,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
       std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
-      bool StorePreamblesInMemory = false,
-      StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false,
-      CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None,
-      ArrayRef<RemappedFile> RemappedFiles = {},
-      bool RemappedFilesKeepOriginalName = true,
-      unsigned PrecompilePreambleAfterNParses = 0,
-      TranslationUnitKind TUKind = TU_Complete,
-      bool CacheCodeCompletionResults = false,
-      bool IncludeBriefCommentsInCodeCompletion = false,
-      bool AllowPCHWithCompilerErrors = false,
-      SkipFunctionBodiesScope SkipFunctionBodies =
-          SkipFunctionBodiesScope::None,
-      bool SingleFileParse = false, bool UserFilesAreVolatile = false,
-      bool ForSerialization = false,
-      bool RetainExcludedConditionalBlocks = false,
-      std::optional<StringRef> ModuleFormat = std::nullopt,
-      std::unique_ptr<ASTUnit> *ErrAST = nullptr,
-      IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
+      bool StorePreamblesInMemory, StringRef PreambleStoragePath,
+      bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
+      ArrayRef<ASTUnit::RemappedFile> RemappedFiles,
+      bool RemappedFilesKeepOriginalName,
+      unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
+      bool CacheCodeCompletionResults,
+      bool IncludeBriefCommentsInCodeCompletion,
+      bool AllowPCHWithCompilerErrors,
+      SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse,
+      bool UserFilesAreVolatile, bool ForSerialization,
+      bool RetainExcludedConditionalBlocks,
+      std::optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
+      IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS);
 
   /// Reparse the source files using the same command-line options that
   /// were originally used to produce this translation unit.
@@ -963,6 +909,44 @@ class ASTUnit {
   bool serialize(raw_ostream &OS);
 };
 
+/// Diagnostic consumer that saves each diagnostic it is given.
+class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer {
+  SmallVectorImpl<StoredDiagnostic> *StoredDiags;
+  SmallVectorImpl<StandaloneDiagnostic> *StandaloneDiags;
+  bool CaptureNonErrorsFromIncludes = true;
+  const LangOptions *LangOpts = nullptr;
+  SourceManager *SourceMgr = nullptr;
+
+public:
+  FilterAndStoreDiagnosticConsumer(
+      SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+      SmallVectorImpl<StandaloneDiagnostic> *StandaloneDiags,
+      bool CaptureNonErrorsFromIncludes);
+
+  void BeginSourceFile(const LangOptions &LangOpts,
+                       const Preprocessor *PP = nullptr) override;
+
+  void HandleDiagnostic(DiagnosticsEngine::Level Level,
+                        const Diagnostic &Info) override;
+};
+
+/// RAII object that optionally captures and filters diagnostics, if
+/// there is no diagnostic client to capture them already.
+class CaptureDroppedDiagnostics {
+  DiagnosticsEngine &Diags;
+  FilterAndStoreDiagnosticConsumer Client;
+  DiagnosticConsumer *PreviousClient = nullptr;
+  std::unique_ptr<DiagnosticConsumer> OwningPreviousClient;
+
+public:
+  CaptureDroppedDiagnostics(
+      CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags,
+      SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+      SmallVectorImpl<StandaloneDiagnostic> *StandaloneDiags);
+
+  ~CaptureDroppedDiagnostics();
+};
+
 } // namespace clang
 
 #endif // LLVM_CLANG_FRONTEND_ASTUNIT_H
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index b19a6e1a8acc3..4977ddb307d21 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -299,16 +299,6 @@ class CompilerInvocation : public CompilerInvocationBase {
                              DiagnosticsEngine &Diags,
                              const char *Argv0 = nullptr);
 
-  /// Get the directory where the compiler headers
-  /// reside, relative to the compiler binary (found by the passed in
-  /// arguments).
-  ///
-  /// \param Argv0 - The program path (from argv[0]), for finding the builtin
-  /// compiler path.
-  /// \param MainAddr - The address of main (or some other function in the main
-  /// executable), for finding the builtin compiler path.
-  static std::string GetResourcesPath(const char *Argv0, void *MainAddr);
-
   /// Populate \p Opts with the default set of pointer authentication-related
   /// options given \p LangOpts and \p Triple.
   ///
diff --git a/clang/include/clang/Frontend/StandaloneDiagnostic.h b/clang/include/clang/Frontend/StandaloneDiagnostic.h
new file mode 100644
index 0000000000000..c23d5f95e0c2f
--- /dev/null
+++ b/clang/include/clang/Frontend/StandaloneDiagnostic.h
@@ -0,0 +1,82 @@
+//===--- StandaloneDiagnostic.h - Serializable Diagnostic -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A serializable diagnostic representation to retain diagnostics after their
+// SourceManager has been destroyed.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H
+#define LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H
+
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/StringExtras.h"
+#include <cassert>
+#include <string>
+#include <vector>
+
+namespace clang {
+
+/// Represents a StoredDiagnostic in a form that can be retained until after its
+/// SourceManager has been destroyed.
+///
+/// Source locations are stored as a combination of filename and offsets into
+/// that file.
+/// To report the diagnostic, it must first be translated back into a
+/// StoredDiagnostic with a new associated SourceManager.
+struct StandaloneDiagnostic {
+  /// Represents a CharSourceRange within a StandaloneDiagnostic.
+  struct SourceOffsetRange {
+    SourceOffsetRange(CharSourceRange Range, const SourceManager &SrcMgr,
+                      const LangOptions &LangOpts);
+
+    unsigned Begin = 0;
+    unsigned End = 0;
+  };
+
+  /// Represents a FixItHint within a StandaloneDiagnostic.
+  struct StandaloneFixIt {
+    StandaloneFixIt(const SourceManager &SrcMgr, const LangOptions &LangOpts,
+                    const FixItHint &FixIt);
+
+    SourceOffsetRange RemoveRange;
+    SourceOffsetRange InsertFromRange;
+    std::string CodeToInsert;
+    bool BeforePreviousInsertions;
+  };
+
+  StandaloneDiagnostic(const LangOptions &LangOpts,
+                       const StoredDiagnostic &InDiag);
+
+  DiagnosticsEngine::Level Level;
+  SrcMgr::CharacteristicKind FileKind;
+  unsigned ID = 0;
+  unsigned FileOffset = 0;
+  std::string Message;
+  std::string Filename;
+  std::vector<SourceOffsetRange> Ranges;
+  std::vector<StandaloneFixIt> FixIts;
+};
+
+/// Translates \c StandaloneDiag into a StoredDiagnostic, associating it with
+/// the provided FileManager and SourceManager.
+///
+/// This allows the diagnostic to be emitted using the diagnostics engine, since
+/// StandaloneDiagnostics themselfs cannot be emitted directly.
+StoredDiagnostic
+translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr,
+                        const StandaloneDiagnostic &StandaloneDiag,
+                        llvm::StringMap<SourceLocation> &SrcLocCache);
+
+} // namespace clang
+
+#endif // STANDALONEDIAGNOSTICS
diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h
index ed2703c76f18d..1c561b47b5c47 100644
--- a/clang/include/clang/Frontend/Utils.h
+++ b/clang/include/clang/Frontend/Utils.h
@@ -192,51 +192,6 @@ IntrusiveRefCntPtr<ExternalSemaSource>
 createChainedIncludesSource(CompilerInstance &CI,
                             IntrusiveRefCntPtr<ASTReader> &OutReader);
 
-/// Optional inputs to createInvocation.
-struct CreateInvocationOptions {
-  /// Receives diagnostics encountered while parsing command-line flags.
-  /// If not provided, these are printed to stderr.
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags = nullptr;
-  /// Used e.g. to probe for system headers locations.
-  /// If not provided, the real filesystem is used.
-  /// FIXME: the driver does perform some non-virtualized IO.
-  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr;
-  /// Whether to attempt to produce a non-null (possibly incorrect) invocation
-  /// if any errors were encountered.
-  /// By default, always return null on errors.
-  bool RecoverOnError = false;
-  /// Allow the driver to probe the filesystem for PCH files.
-  /// This is used to replace -include with -include-pch in the cc1 args.
-  /// FIXME: ProbePrecompiled=true is a poor, historical default.
-  /// It misbehaves if the PCH file is from GCC, has the wrong version, etc.
-  bool ProbePrecompiled = false;
-  /// If set, the target is populated with the cc1 args produced by the driver.
-  /// This may be populated even if createInvocation returns nullptr.
-  std::vector<std::string> *CC1Args = nullptr;
-};
-
-/// Interpret clang arguments in preparation to parse a file.
-///
-/// This simulates a number of steps Clang takes when its driver is invoked:
-/// - choosing actions (e.g compile + link) to run
-/// - probing the system for settings like standard library locations
-/// - spawning a cc1 subprocess to compile code, with more explicit arguments
-/// - in the cc1 process, assembling those arguments into a CompilerInvocation
-///   which is used to configure the parser
-///
-/// This simulation is lossy, e.g. in some situations one driver run would
-/// result in multiple parses. (Multi-arch, CUDA, ...).
-/// This function tries to select a reasonable invocation that tools should use.
-///
-/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++".
-/// Absolute path is preferred - this affects searching for system headers.
-///
-/// May return nullptr if an invocation could not be determined.
-/// See CreateInvocationOptions::ShouldRecoverOnErrors to try harder!
-std::unique_ptr<CompilerInvocation>
-createInvocation(ArrayRef<const char *> Args,
-                 CreateInvocationOptions Opts = {});
-
 } // namespace clang
 
 #endif // LLVM_CLANG_FRONTEND_UTILS_H
diff --git a/clang/include/clang/Options/OptionUtils.h b/clang/include/clang/Options/OptionUtils.h
index 83c48bd7d6843..02c9c27554db1 100644
--- a/clang/include/clang/Options/OptionUtils.h
+++ b/clang/include/clang/Options/OptionUtils.h
@@ -28,6 +28,7 @@ class ArgList;
 } // namespace llvm
 
 namespace clang {
+
 /// Return the value of the last argument as an integer, or a default. If Diags
 /// is non-null, emits an error if the argument is given, but non-integral.
 int getLastArgIntValue(const llvm::opt::ArgList &Args,
@@ -53,6 +54,29 @@ inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args,
   return getLastArgUInt64Value(Args, Id, Default, &Diags, Base);
 }
 
+// Parse -mprefer-vector-width=. Return the Value string if well-formed.
+// Otherwise, return an empty string and issue a diagnosic message if needed.
+StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
+                                        const llvm::opt::ArgList &Args);
+
+// Parse -mrecip. Return the Value string if well-formed.
+// Otherwise, return an empty string and issue a diagnosic message if needed.
+StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags,
+                            const llvm::opt::ArgList &Args);
+
+/// Get the directory where the compiler headers reside, relative to the
+/// compiler binary path \p BinaryPath.
+std::string GetResourcesPath(StringRef BinaryPath);
+
+/// Get the directory where the compiler headers reside, relative to the
+/// compiler binary path (found by the passed in arguments).
+///
+/// \param Argv0 The program path (from argv[0]), for finding the builtin
+/// compiler path.
+/// \param MainAddr The address of main (or some other function in the main
+/// executable), for finding the builtin compiler path.
+std::string GetResourcesPath(const char *Argv0, void *MainAddr);
+
 } // namespace clang
 
 #endif // LLVM_CLANG_OPTIONS_OPTIONUTILS_H
diff --git a/clang/lib/CrossTU/CMakeLists.txt b/clang/lib/CrossTU/CMakeLists.txt
index 3349fc283925d..eef7a892701fb 100644
--- a/clang/lib/CrossTU/CMakeLists.txt
+++ b/clang/lib/CrossTU/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangCrossTU
   LINK_LIBS
   clangAST
   clangBasic
+  clangDriver
   clangFrontend
   clangIndex
   )
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index 0287845a741ed..a3fc2cf6bfb3c 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -16,6 +16,7 @@
 #include "clang/Basic/DiagnosticDriver.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CrossTU/CrossTUDiagnostic.h"
+#include "clang/Driver/CreateASTUnitFromArgs.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -619,7 +620,7 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource(
   auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(DiagID, *DiagOpts,
                                                             DiagClient);
 
-  return ASTUnit::LoadFromCommandLine(
+  return CreateASTUnitFromCommandLine(
       CommandLineArgs.begin(), (CommandLineArgs.end()),
       CI.getPCHContainerOperations(), DiagOpts, Diags,
       CI.getHeaderSearchOpts().ResourceDir);
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 8052659e9836b..d987111827597 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -17,6 +17,8 @@ endif()
 add_clang_library(clangDriver
   Action.cpp
   Compilation.cpp
+  CreateASTUnitFromArgs.cpp
+  CreateInvocationFromArgs.cpp
   Distro.cpp
   Driver.cpp
   Job.cpp
@@ -96,6 +98,8 @@ add_clang_library(clangDriver
 
   LINK_LIBS
   clangBasic
+  clangFrontend
+  clangSerialization
   clangLex
   clangOptions
   ${system_libs}
diff --git a/clang/lib/Driver/CreateASTUnitFromArgs.cpp b/clang/lib/Driver/CreateASTUnitFromArgs.cpp
new file mode 100644
index 0000000000000..ea31a8ed07c5f
--- /dev/null
+++ b/clang/lib/Driver/CreateASTUnitFromArgs.cpp
@@ -0,0 +1,166 @@
+//===--- CreateASTUnitFromArgs.h - Create an ASTUnit from Args ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for creating an ASTUnit from a vector of command line arguments.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/CreateASTUnitFromArgs.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Serialization/ModuleCache.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+
+using namespace clang;
+
+/// Create an ASTUnit from a vector of command line arguments, which must
+/// specify exactly one source file.
+///
+/// \param ArgBegin - The beginning of the argument vector.
+///
+/// \param ArgEnd - The end of the argument vector.
+///
+/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
+/// creating modules.
+///
+/// \param Diags - The diagnostics engine to use for reporting errors; its
+/// lifetime is expected to extend past that of the returned ASTUnit.
+///
+/// \param ResourceFilesPath - The path to the compiler resource files.
+///
+/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false,
+/// PCH are stored in temporary files.
+///
+/// \param PreambleStoragePath - The path to a directory, in which to create
+/// temporary PCH files. If empty, the default system temporary directory is
+/// used. This parameter is ignored if \p StorePreamblesInMemory is true.
+///
+/// \param ModuleFormat - If provided, uses the specific module format.
+///
+/// \param ErrAST - If non-null and parsing failed without any AST to return
+/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
+/// mainly to allow the caller to see the diagnostics.
+///
+/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses.
+/// Note that preamble is saved to a temporary directory on a RealFileSystem,
+/// so in order for it to be loaded correctly, VFS should have access to
+/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used
+/// if \p VFS is nullptr.
+///
+// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
+// shouldn't need to specify them at construction time.
+std::unique_ptr<ASTUnit> clang::CreateASTUnitFromCommandLine(
+    const char **ArgBegin, const char **ArgEnd,
+    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
+    bool StorePreamblesInMemory, StringRef PreambleStoragePath,
+    bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
+    ArrayRef<ASTUnit::RemappedFile> RemappedFiles,
+    bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses,
+    TranslationUnitKind TUKind, bool CacheCodeCompletionResults,
+    bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors,
+    SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse,
+    bool UserFilesAreVolatile, bool ForSerialization,
+    bool RetainExcludedConditionalBlocks, std::optional<StringRef> ModuleFormat,
+    std::unique_ptr<ASTUnit> *ErrAST,
+    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+  assert(Diags.get() && "no DiagnosticsEngine was provided");
+
+  // If no VFS was provided, create one that tracks the physical file system.
+  // If '-working-directory' was passed as an argument, 'createInvocation' will
+  // set this as the current working directory of the VFS.
+  if (!VFS)
+    VFS = llvm::vfs::createPhysicalFileSystem();
+
+  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+
+  std::shared_ptr<CompilerInvocation> CI;
+
+  {
+    CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
+                                      &StoredDiagnostics, nullptr);
+
+    CreateInvocationOptions CIOpts;
+    CIOpts.VFS = VFS;
+    CIOpts.Diags = Diags;
+    CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
+    CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts));
+    if (!CI)
+      return nullptr;
+  }
+
+  // Override any files that need remapping
+  for (const auto &RemappedFile : RemappedFiles) {
+    CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
+                                              RemappedFile.second);
+  }
+  PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
+  PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
+  PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
+  PPOpts.SingleFileParseMode = SingleFileParse;
+  PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks;
+
+  // Override the resources path.
+  CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath);
+
+  CI->getFrontendOpts().SkipFunctionBodies =
+      SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile;
+
+  if (ModuleFormat)
+    CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat);
+
+  // Create the AST unit.
+  std::unique_ptr<ASTUnit> AST;
+  AST.reset(new ASTUnit(false));
+  AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
+  AST->StoredDiagnostics.swap(StoredDiagnostics);
+  ASTUnit::ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+  AST->DiagOpts = DiagOpts;
+  AST->Diagnostics = Diags;
+  AST->FileSystemOpts = CI->getFileSystemOpts();
+  AST->CodeGenOpts = std::make_unique<CodeGenOptions>(CI->getCodeGenOpts());
+  VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
+  AST->FileMgr =
+      llvm::makeIntrusiveRefCnt<FileManager>(AST->FileSystemOpts, VFS);
+  AST->StorePreamblesInMemory = StorePreamblesInMemory;
+  AST->PreambleStoragePath = PreambleStoragePath;
+  AST->ModCache = createCrossProcessModuleCache();
+  AST->OnlyLocalDecls = OnlyLocalDecls;
+  AST->CaptureDiagnostics = CaptureDiagnostics;
+  AST->TUKind = TUKind;
+  AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
+  AST->IncludeBriefCommentsInCodeCompletion =
+      IncludeBriefCommentsInCodeCompletion;
+  AST->UserFilesAreVolatile = UserFilesAreVolatile;
+  AST->Invocation = CI;
+  AST->SkipFunctionBodies = SkipFunctionBodies;
+  if (ForSerialization)
+    AST->WriterData.reset(
+        new ASTUnit::ASTWriterData(*AST->ModCache, *AST->CodeGenOpts));
+  // Zero out now to ease cleanup during crash recovery.
+  CI = nullptr;
+  Diags = nullptr;
+
+  // Recover resources if we crash before exiting this method.
+  llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get());
+
+  if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
+                                      PrecompilePreambleAfterNParses, VFS)) {
+    // Some error occurred, if caller wants to examine diagnostics, pass it the
+    // ASTUnit.
+    if (ErrAST) {
+      AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
+      ErrAST->swap(AST);
+    }
+    return nullptr;
+  }
+
+  return AST;
+}
diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Driver/CreateInvocationFromArgs.cpp
similarity index 93%
rename from clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
rename to clang/lib/Driver/CreateInvocationFromArgs.cpp
index e54e83151ad1e..516d61f1a1159 100644
--- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/clang/lib/Driver/CreateInvocationFromArgs.cpp
@@ -1,4 +1,4 @@
-//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==//
+//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,9 +10,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Driver/Action.h"
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/Tool.h"
@@ -24,12 +24,13 @@
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/Host.h"
-using namespace clang;
+
 using namespace llvm::opt;
 
+namespace clang {
+
 std::unique_ptr<CompilerInvocation>
-clang::createInvocation(ArrayRef<const char *> ArgList,
-                        CreateInvocationOptions Opts) {
+createInvocation(ArrayRef<const char *> ArgList, CreateInvocationOptions Opts) {
   assert(!ArgList.empty());
   std::optional<DiagnosticOptions> LocalDiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
@@ -114,3 +115,5 @@ clang::createInvocation(ArrayRef<const char *> ArgList,
     return nullptr;
   return CI;
 }
+
+} // namespace clang
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index de8d4601210ae..c6dd66d9efef3 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -66,6 +66,7 @@
 #include "clang/Driver/ToolChain.h"
 #include "clang/Driver/Types.h"
 #include "clang/Lex/DependencyDirectivesScanner.h"
+#include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
@@ -125,40 +126,6 @@ template <typename F> static bool usesInput(const ArgList &Args, F &&Fn) {
   });
 }
 
-// static
-std::string Driver::GetResourcesPath(StringRef BinaryPath) {
-  // Since the resource directory is embedded in the module hash, it's important
-  // that all places that need it call this function, so that they get the
-  // exact same string ("a/../b/" and "b/" get different hashes, for example).
-
-  // Dir is bin/ or lib/, depending on where BinaryPath is.
-  StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
-  SmallString<128> P(Dir);
-
-  StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR);
-  if (!ConfiguredResourceDir.empty()) {
-    // FIXME: We should fix the behavior of llvm::sys::path::append so we don't
-    // need to check for absolute paths here.
-    if (llvm::sys::path::is_absolute(ConfiguredResourceDir))
-      P = ConfiguredResourceDir;
-    else
-      llvm::sys::path::append(P, ConfiguredResourceDir);
-  } else {
-    // On Windows, libclang.dll is in bin/.
-    // On non-Windows, libclang.so/.dylib is in lib/.
-    // With a static-library build of libclang, LibClangPath will contain the
-    // path of the embedding binary, which for LLVM binaries will be in bin/.
-    // ../lib gets us to lib/ in both cases.
-    P = llvm::sys::path::parent_path(Dir);
-    // This search path is also created in the COFF driver of lld, so any
-    // changes here also needs to happen in lld/COFF/Driver.cpp
-    llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
-                            CLANG_VERSION_MAJOR_STRING);
-  }
-
-  return std::string(P);
-}
-
 CUIDOptions::CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D)
     : UseCUID(Kind::Hash) {
   if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) {
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..2f0aec3ec3c37 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -32,6 +32,7 @@
 #include "clang/Driver/SanitizerArgs.h"
 #include "clang/Driver/Types.h"
 #include "clang/Driver/XRayArgs.h"
+#include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallSet.h"
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 4c036f0f8dee3..d3539a594df11 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -3398,169 +3398,6 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args,
     CmdArgs.push_back("-floop-interchange");
 }
 
-// Parse -mprefer-vector-width=. Return the Value string if well-formed.
-// Otherwise, return an empty string and issue a diagnosic message if needed.
-StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
-                                               const llvm::opt::ArgList &Args) {
-  Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ);
-  if (!A)
-    return "";
-
-  StringRef Value = A->getValue();
-  unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED;
-
-  // Only "none" and Integer values are accepted by
-  // -mprefer-vector-width=<value>.
-  if (Value != "none" && Value.getAsInteger(10, Width)) {
-    Diags.Report(clang::diag::err_drv_invalid_value)
-        << A->getOption().getName() << Value;
-    return "";
-  }
-
-  return Value;
-}
-
-// This is a helper function for validating the optional refinement step
-// parameter in reciprocal argument strings. Return false if there is an error
-// parsing the refinement step. Otherwise, return true and set the Position
-// of the refinement step in the input string.
-static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags,
-                              const Arg &A, size_t &Position) {
-  const char RefinementStepToken = ':';
-  Position = In.find(RefinementStepToken);
-  if (Position != StringRef::npos) {
-    StringRef Option = A.getOption().getName();
-    StringRef RefStep = In.substr(Position + 1);
-    // Allow exactly one numeric character for the additional refinement
-    // step parameter. This is reasonable for all currently-supported
-    // operations and architectures because we would expect that a larger value
-    // of refinement steps would cause the estimate "optimization" to
-    // under-perform the native operation. Also, if the estimate does not
-    // converge quickly, it probably will not ever converge, so further
-    // refinement steps will not produce a better answer.
-    if (RefStep.size() != 1) {
-      Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
-      return false;
-    }
-    char RefStepChar = RefStep[0];
-    if (RefStepChar < '0' || RefStepChar > '9') {
-      Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
-      return false;
-    }
-  }
-  return true;
-}
-
-// Parse -mrecip. Return the Value string if well-formed.
-// Otherwise, return an empty string and issue a diagnosic message if needed.
-StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags,
-                                   const ArgList &Args) {
-  StringRef DisabledPrefixIn = "!";
-  StringRef DisabledPrefixOut = "!";
-  StringRef EnabledPrefixOut = "";
-  StringRef Out = "";
-
-  Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
-  if (!A)
-    return "";
-
-  unsigned NumOptions = A->getNumValues();
-  if (NumOptions == 0) {
-    // No option is the same as "all".
-    return "all";
-  }
-
-  // Pass through "all", "none", or "default" with an optional refinement step.
-  if (NumOptions == 1) {
-    StringRef Val = A->getValue(0);
-    size_t RefStepLoc;
-    if (!getRefinementStep(Val, Diags, *A, RefStepLoc))
-      return "";
-    StringRef ValBase = Val.slice(0, RefStepLoc);
-    if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
-      return Val;
-    }
-  }
-
-  // Each reciprocal type may be enabled or disabled individually.
-  // Check each input value for validity, concatenate them all back together,
-  // and pass through.
-
-  llvm::StringMap<bool> OptionStrings;
-  OptionStrings.insert(std::make_pair("divd", false));
-  OptionStrings.insert(std::make_pair("divf", false));
-  OptionStrings.insert(std::make_pair("divh", false));
-  OptionStrings.insert(std::make_pair("vec-divd", false));
-  OptionStrings.insert(std::make_pair("vec-divf", false));
-  OptionStrings.insert(std::make_pair("vec-divh", false));
-  OptionStrings.insert(std::make_pair("sqrtd", false));
-  OptionStrings.insert(std::make_pair("sqrtf", false));
-  OptionStrings.insert(std::make_pair("sqrth", false));
-  OptionStrings.insert(std::make_pair("vec-sqrtd", false));
-  OptionStrings.insert(std::make_pair("vec-sqrtf", false));
-  OptionStrings.insert(std::make_pair("vec-sqrth", false));
-
-  for (unsigned i = 0; i != NumOptions; ++i) {
-    StringRef Val = A->getValue(i);
-
-    bool IsDisabled = Val.starts_with(DisabledPrefixIn);
-    // Ignore the disablement token for string matching.
-    if (IsDisabled)
-      Val = Val.substr(1);
-
-    size_t RefStep;
-    if (!getRefinementStep(Val, Diags, *A, RefStep))
-      return "";
-
-    StringRef ValBase = Val.slice(0, RefStep);
-    llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
-    if (OptionIter == OptionStrings.end()) {
-      // Try again specifying float suffix.
-      OptionIter = OptionStrings.find(ValBase.str() + 'f');
-      if (OptionIter == OptionStrings.end()) {
-        // The input name did not match any known option string.
-        Diags.Report(diag::err_drv_unknown_argument) << Val;
-        return "";
-      }
-      // The option was specified without a half or float or double suffix.
-      // Make sure that the double or half entry was not already specified.
-      // The float entry will be checked below.
-      if (OptionStrings[ValBase.str() + 'd'] ||
-          OptionStrings[ValBase.str() + 'h']) {
-        Diags.Report(diag::err_drv_invalid_value)
-            << A->getOption().getName() << Val;
-        return "";
-      }
-    }
-
-    if (OptionIter->second == true) {
-      // Duplicate option specified.
-      Diags.Report(diag::err_drv_invalid_value)
-          << A->getOption().getName() << Val;
-      return "";
-    }
-
-    // Mark the matched option as found. Do not allow duplicate specifiers.
-    OptionIter->second = true;
-
-    // If the precision was not specified, also mark the double and half entry
-    // as found.
-    if (ValBase.back() != 'f' && ValBase.back() != 'd' &&
-        ValBase.back() != 'h') {
-      OptionStrings[ValBase.str() + 'd'] = true;
-      OptionStrings[ValBase.str() + 'h'] = true;
-    }
-
-    // Build the output string.
-    StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
-    Out = Args.MakeArgString(Out + Prefix + Val);
-    if (i != NumOptions - 1)
-      Out = Args.MakeArgString(Out + ",");
-  }
-
-  return Out;
-}
-
 std::string tools::complexRangeKindToStr(LangOptions::ComplexRangeKind Range) {
   switch (Range) {
   case LangOptions::ComplexRangeKind::CX_Full:
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index cc4755cd6a9b0..438de23be0103 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -11,6 +11,7 @@
 
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/Driver/CommonArgs.h"
+#include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
 #include "llvm/Frontend/Debug/Options.h"
 #include "llvm/Support/Path.h"
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 1de779ccbf141..e72317da64596 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -44,6 +44,7 @@
 #include "clang/Frontend/FrontendOptions.h"
 #include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/Frontend/StandaloneDiagnostic.h"
 #include "clang/Frontend/Utils.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/HeaderSearchOptions.h"
@@ -210,15 +211,6 @@ getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
   return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
 }
 
-struct ASTUnit::ASTWriterData {
-  SmallString<128> Buffer;
-  llvm::BitstreamWriter Stream;
-  ASTWriter Writer;
-
-  ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts)
-      : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {}
-};
-
 void ASTUnit::clearFileLevelDecls() {
   FileDecls.clear();
 }
@@ -581,73 +573,24 @@ class ASTInfoCollector : public ASTReaderListener {
     Counter = NewCounter;
   }
 };
+} // anonymous namespace
 
-/// Diagnostic consumer that saves each diagnostic it is given.
-class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer {
-  SmallVectorImpl<StoredDiagnostic> *StoredDiags;
-  SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags;
-  bool CaptureNonErrorsFromIncludes = true;
-  const LangOptions *LangOpts = nullptr;
-  SourceManager *SourceMgr = nullptr;
-
-public:
-  FilterAndStoreDiagnosticConsumer(
-      SmallVectorImpl<StoredDiagnostic> *StoredDiags,
-      SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags,
-      bool CaptureNonErrorsFromIncludes)
-      : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
-        CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) {
-    assert((StoredDiags || StandaloneDiags) &&
-           "No output collections were passed to StoredDiagnosticConsumer.");
-  }
-
-  void BeginSourceFile(const LangOptions &LangOpts,
-                       const Preprocessor *PP = nullptr) override {
-    this->LangOpts = &LangOpts;
-    if (PP)
-      SourceMgr = &PP->getSourceManager();
-  }
-
-  void HandleDiagnostic(DiagnosticsEngine::Level Level,
-                        const Diagnostic &Info) override;
-};
-
-/// RAII object that optionally captures and filters diagnostics, if
-/// there is no diagnostic client to capture them already.
-class CaptureDroppedDiagnostics {
-  DiagnosticsEngine &Diags;
-  FilterAndStoreDiagnosticConsumer Client;
-  DiagnosticConsumer *PreviousClient = nullptr;
-  std::unique_ptr<DiagnosticConsumer> OwningPreviousClient;
-
-public:
-  CaptureDroppedDiagnostics(
-      CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags,
-      SmallVectorImpl<StoredDiagnostic> *StoredDiags,
-      SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
-      : Diags(Diags),
-        Client(StoredDiags, StandaloneDiags,
-               CaptureDiagnostics !=
-                   CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) {
-    if (CaptureDiagnostics != CaptureDiagsKind::None ||
-        Diags.getClient() == nullptr) {
-      OwningPreviousClient = Diags.takeClient();
-      PreviousClient = Diags.getClient();
-      Diags.setClient(&Client, false);
-    }
-  }
-
-  ~CaptureDroppedDiagnostics() {
-    if (Diags.getClient() == &Client)
-      Diags.setClient(PreviousClient, !!OwningPreviousClient.release());
-  }
-};
-
-} // namespace
+FilterAndStoreDiagnosticConsumer::FilterAndStoreDiagnosticConsumer(
+    SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+    SmallVectorImpl<StandaloneDiagnostic> *StandaloneDiags,
+    bool CaptureNonErrorsFromIncludes)
+    : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
+      CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) {
+  assert((StoredDiags || StandaloneDiags) &&
+         "No output collections were passed to StoredDiagnosticConsumer.");
+}
 
-static ASTUnit::StandaloneDiagnostic
-makeStandaloneDiagnostic(const LangOptions &LangOpts,
-                         const StoredDiagnostic &InDiag);
+void FilterAndStoreDiagnosticConsumer::BeginSourceFile(
+    const LangOptions &LangOpts, const Preprocessor *PP) {
+  this->LangOpts = &LangOpts;
+  if (PP)
+    SourceMgr = &PP->getSourceManager();
+}
 
 static bool isInMainFile(const clang::Diagnostic &D) {
   if (!D.hasSourceManager() || !D.getLocation().isValid())
@@ -683,12 +626,32 @@ void FilterAndStoreDiagnosticConsumer::HandleDiagnostic(
         StoredDiag.emplace(Level, Info);
         ResultDiag = &*StoredDiag;
       }
-      StandaloneDiags->push_back(
-          makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
+      StandaloneDiags->emplace_back(*LangOpts, *ResultDiag);
     }
   }
 }
 
+CaptureDroppedDiagnostics::CaptureDroppedDiagnostics(
+    CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags,
+    SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+    SmallVectorImpl<StandaloneDiagnostic> *StandaloneDiags)
+    : Diags(Diags),
+      Client(StoredDiags, StandaloneDiags,
+             CaptureDiagnostics !=
+                 CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) {
+  if (CaptureDiagnostics != CaptureDiagsKind::None ||
+      Diags.getClient() == nullptr) {
+    OwningPreviousClient = Diags.takeClient();
+    PreviousClient = Diags.getClient();
+    Diags.setClient(&Client, false);
+  }
+}
+
+CaptureDroppedDiagnostics::~CaptureDroppedDiagnostics() {
+  if (Diags.getClient() == &Client)
+    Diags.setClient(PreviousClient, !!OwningPreviousClient.release());
+}
+
 IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
   return Reader;
 }
@@ -1110,7 +1073,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks {
   unsigned Hash = 0;
   std::vector<Decl *> TopLevelDecls;
   std::vector<LocalDeclID> TopLevelDeclIDs;
-  llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags;
+  llvm::SmallVector<StandaloneDiagnostic, 4> PreambleDiags;
 };
 
 } // namespace
@@ -1259,10 +1222,17 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
   if (!Act->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
     return true;
 
-  if (SavedMainFileBuffer)
-    TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
-                               PreambleDiagnostics, StoredDiagnostics);
-  else
+  if (SavedMainFileBuffer) {
+    StoredDiagnostics.clear();
+    StoredDiagnostics.reserve(PreambleDiagnostics.size());
+    llvm::transform(std::move(PreambleDiagnostics),
+                    std::back_inserter(StoredDiagnostics),
+                    [&](auto &&StandaloneDiag) {
+                      return translateStandaloneDiag(
+                          getFileManager(), getSourceManager(),
+                          std::move(StandaloneDiag), PreambleSrcLocCache);
+                    });
+  } else
     PreambleSrcLocCache.clear();
 
   if (llvm::Error Err = Act->Execute()) {
@@ -1281,51 +1251,6 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
   return false;
 }
 
-static std::pair<unsigned, unsigned>
-makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
-                    const LangOptions &LangOpts) {
-  CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts);
-  unsigned Offset = SM.getFileOffset(FileRange.getBegin());
-  unsigned EndOffset = SM.getFileOffset(FileRange.getEnd());
-  return std::make_pair(Offset, EndOffset);
-}
-
-static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM,
-                                                    const LangOptions &LangOpts,
-                                                    const FixItHint &InFix) {
-  ASTUnit::StandaloneFixIt OutFix;
-  OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts);
-  OutFix.InsertFromRange =
-      makeStandaloneRange(InFix.InsertFromRange, SM, LangOpts);
-  OutFix.CodeToInsert = InFix.CodeToInsert;
-  OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions;
-  return OutFix;
-}
-
-static ASTUnit::StandaloneDiagnostic
-makeStandaloneDiagnostic(const LangOptions &LangOpts,
-                         const StoredDiagnostic &InDiag) {
-  ASTUnit::StandaloneDiagnostic OutDiag;
-  OutDiag.ID = InDiag.getID();
-  OutDiag.Level = InDiag.getLevel();
-  OutDiag.Message = std::string(InDiag.getMessage());
-  OutDiag.LocOffset = 0;
-  if (InDiag.getLocation().isInvalid())
-    return OutDiag;
-  const SourceManager &SM = InDiag.getLocation().getManager();
-  SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation());
-  OutDiag.Filename = std::string(SM.getFilename(FileLoc));
-  if (OutDiag.Filename.empty())
-    return OutDiag;
-  OutDiag.LocOffset = SM.getFileOffset(FileLoc);
-  for (const auto &Range : InDiag.getRanges())
-    OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts));
-  for (const auto &FixIt : InDiag.getFixIts())
-    OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt));
-
-  return OutDiag;
-}
-
 /// Attempt to build or re-use a precompiled preamble when (re-)parsing
 /// the source file.
 ///
@@ -1780,114 +1705,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
   return AST;
 }
 
-std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
-    const char **ArgBegin, const char **ArgEnd,
-    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    std::shared_ptr<DiagnosticOptions> DiagOpts,
-    IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
-    bool StorePreamblesInMemory, StringRef PreambleStoragePath,
-    bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
-    ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName,
-    unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
-    bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
-    bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies,
-    bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
-    bool RetainExcludedConditionalBlocks, std::optional<StringRef> ModuleFormat,
-    std::unique_ptr<ASTUnit> *ErrAST,
-    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
-  assert(Diags.get() && "no DiagnosticsEngine was provided");
-
-  // If no VFS was provided, create one that tracks the physical file system.
-  // If '-working-directory' was passed as an argument, 'createInvocation' will
-  // set this as the current working directory of the VFS.
-  if (!VFS)
-    VFS = llvm::vfs::createPhysicalFileSystem();
-
-  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
-
-  std::shared_ptr<CompilerInvocation> CI;
-
-  {
-    CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
-                                      &StoredDiagnostics, nullptr);
-
-    CreateInvocationOptions CIOpts;
-    CIOpts.VFS = VFS;
-    CIOpts.Diags = Diags;
-    CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
-    CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts));
-    if (!CI)
-      return nullptr;
-  }
-
-  // Override any files that need remapping
-  for (const auto &RemappedFile : RemappedFiles) {
-    CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
-                                              RemappedFile.second);
-  }
-  PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
-  PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
-  PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
-  PPOpts.SingleFileParseMode = SingleFileParse;
-  PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks;
-
-  // Override the resources path.
-  CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath);
-
-  CI->getFrontendOpts().SkipFunctionBodies =
-      SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile;
-
-  if (ModuleFormat)
-    CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat);
-
-  // Create the AST unit.
-  std::unique_ptr<ASTUnit> AST;
-  AST.reset(new ASTUnit(false));
-  AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
-  AST->StoredDiagnostics.swap(StoredDiagnostics);
-  ConfigureDiags(Diags, *AST, CaptureDiagnostics);
-  AST->DiagOpts = DiagOpts;
-  AST->Diagnostics = Diags;
-  AST->FileSystemOpts = CI->getFileSystemOpts();
-  AST->CodeGenOpts = std::make_unique<CodeGenOptions>(CI->getCodeGenOpts());
-  VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
-  AST->FileMgr =
-      llvm::makeIntrusiveRefCnt<FileManager>(AST->FileSystemOpts, VFS);
-  AST->StorePreamblesInMemory = StorePreamblesInMemory;
-  AST->PreambleStoragePath = PreambleStoragePath;
-  AST->ModCache = createCrossProcessModuleCache();
-  AST->OnlyLocalDecls = OnlyLocalDecls;
-  AST->CaptureDiagnostics = CaptureDiagnostics;
-  AST->TUKind = TUKind;
-  AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
-  AST->IncludeBriefCommentsInCodeCompletion =
-      IncludeBriefCommentsInCodeCompletion;
-  AST->UserFilesAreVolatile = UserFilesAreVolatile;
-  AST->Invocation = CI;
-  AST->SkipFunctionBodies = SkipFunctionBodies;
-  if (ForSerialization)
-    AST->WriterData.reset(new ASTWriterData(*AST->ModCache, *AST->CodeGenOpts));
-  // Zero out now to ease cleanup during crash recovery.
-  CI = nullptr;
-  Diags = nullptr;
-
-  // Recover resources if we crash before exiting this method.
-  llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get());
-
-  if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
-                                      PrecompilePreambleAfterNParses, VFS)) {
-    // Some error occurred, if caller wants to examine diagnostics, pass it the
-    // ASTUnit.
-    if (ErrAST) {
-      AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
-      ErrAST->swap(AST);
-    }
-    return nullptr;
-  }
-
-  return AST;
-}
-
 bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                       ArrayRef<RemappedFile> RemappedFiles,
                       IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
@@ -2406,64 +2223,6 @@ bool ASTUnit::serialize(raw_ostream &OS) {
   return serializeUnit(Writer, Buffer, getSema(), OS);
 }
 
-void ASTUnit::TranslateStoredDiagnostics(
-    FileManager &FileMgr, SourceManager &SrcMgr,
-    const SmallVectorImpl<StandaloneDiagnostic> &Diags,
-    SmallVectorImpl<StoredDiagnostic> &Out) {
-  // Map the standalone diagnostic into the new source manager. We also need to
-  // remap all the locations to the new view. This includes the diag location,
-  // any associated source ranges, and the source ranges of associated fix-its.
-  // FIXME: There should be a cleaner way to do this.
-  SmallVector<StoredDiagnostic, 4> Result;
-  Result.reserve(Diags.size());
-
-  for (const auto &SD : Diags) {
-    // Rebuild the StoredDiagnostic.
-    if (SD.Filename.empty())
-      continue;
-    auto FE = FileMgr.getOptionalFileRef(SD.Filename);
-    if (!FE)
-      continue;
-    SourceLocation FileLoc;
-    auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
-    if (ItFileID == PreambleSrcLocCache.end()) {
-      FileID FID = SrcMgr.translateFile(*FE);
-      FileLoc = SrcMgr.getLocForStartOfFile(FID);
-      PreambleSrcLocCache[SD.Filename] = FileLoc;
-    } else {
-      FileLoc = ItFileID->getValue();
-    }
-
-    if (FileLoc.isInvalid())
-      continue;
-    SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset);
-    FullSourceLoc Loc(L, SrcMgr);
-
-    SmallVector<CharSourceRange, 4> Ranges;
-    Ranges.reserve(SD.Ranges.size());
-    for (const auto &Range : SD.Ranges) {
-      SourceLocation BL = FileLoc.getLocWithOffset(Range.first);
-      SourceLocation EL = FileLoc.getLocWithOffset(Range.second);
-      Ranges.push_back(CharSourceRange::getCharRange(BL, EL));
-    }
-
-    SmallVector<FixItHint, 2> FixIts;
-    FixIts.reserve(SD.FixIts.size());
-    for (const auto &FixIt : SD.FixIts) {
-      FixIts.push_back(FixItHint());
-      FixItHint &FH = FixIts.back();
-      FH.CodeToInsert = FixIt.CodeToInsert;
-      SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first);
-      SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second);
-      FH.RemoveRange = CharSourceRange::getCharRange(BL, EL);
-    }
-
-    Result.push_back(
-        StoredDiagnostic(SD.Level, SD.ID, SD.Message, Loc, Ranges, FixIts));
-  }
-  Result.swap(Out);
-}
-
 void ASTUnit::addFileLevelDecl(Decl *D) {
   assert(D);
 
diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt
index dac9e0d26f393..634f239933605 100644
--- a/clang/lib/Frontend/CMakeLists.txt
+++ b/clang/lib/Frontend/CMakeLists.txt
@@ -17,7 +17,6 @@ add_clang_library(clangFrontend
   ChainedIncludesSource.cpp
   CompilerInstance.cpp
   CompilerInvocation.cpp
-  CreateInvocationFromCommandLine.cpp
   DependencyFile.cpp
   DependencyGraph.cpp
   DiagnosticRenderer.cpp
@@ -36,6 +35,7 @@ add_clang_library(clangFrontend
   SARIFDiagnosticPrinter.cpp
   SerializedDiagnosticPrinter.cpp
   SerializedDiagnosticReader.cpp
+  StandaloneDiagnostic.cpp
   TestModuleFileExtension.cpp
   TextDiagnostic.cpp
   TextDiagnosticBuffer.cpp
@@ -51,7 +51,6 @@ add_clang_library(clangFrontend
   clangAPINotes
   clangAST
   clangBasic
-  clangDriver
   clangOptions
   clangEdit
   clangLex
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index c7c29a91721c0..5f1c7afdc80a3 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -27,7 +27,6 @@
 #include "clang/Basic/Version.h"
 #include "clang/Basic/XRayInstr.h"
 #include "clang/Config/config.h"
-#include "clang/Driver/Driver.h"
 #include "clang/Frontend/CommandLineSourceLoc.h"
 #include "clang/Frontend/DependencyOutputOptions.h"
 #include "clang/Frontend/FrontendOptions.h"
@@ -3273,13 +3272,6 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
-std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
-                                                 void *MainAddr) {
-  std::string ClangExecutable =
-      llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
-  return driver::Driver::GetResourcesPath(ClangExecutable);
-}
-
 static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
                                      ArgumentConsumer Consumer) {
   const HeaderSearchOptions *HeaderSearchOpts = &Opts;
diff --git a/clang/lib/Frontend/StandaloneDiagnostic.cpp b/clang/lib/Frontend/StandaloneDiagnostic.cpp
new file mode 100644
index 0000000000000..4f19c91b7d266
--- /dev/null
+++ b/clang/lib/Frontend/StandaloneDiagnostic.cpp
@@ -0,0 +1,117 @@
+//===--- StandaloneDiagnostic.h - Serializable Diagnostic ------------- ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/StandaloneDiagnostic.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+
+StandaloneDiagnostic::SourceOffsetRange::SourceOffsetRange(
+    CharSourceRange Range, const SourceManager &SrcMgr,
+    const LangOptions &LangOpts) {
+  const auto FileRange = Lexer::makeFileCharRange(Range, SrcMgr, LangOpts);
+  Begin = SrcMgr.getFileOffset(FileRange.getBegin());
+  End = SrcMgr.getFileOffset(FileRange.getEnd());
+}
+
+StandaloneDiagnostic::StandaloneFixIt::StandaloneFixIt(
+    const SourceManager &SrcMgr, const LangOptions &LangOpts,
+    const FixItHint &FixIt)
+    : RemoveRange(FixIt.RemoveRange, SrcMgr, LangOpts),
+      InsertFromRange(FixIt.InsertFromRange, SrcMgr, LangOpts),
+      CodeToInsert(FixIt.CodeToInsert),
+      BeforePreviousInsertions(FixIt.BeforePreviousInsertions) {}
+
+StandaloneDiagnostic::StandaloneDiagnostic(const LangOptions &LangOpts,
+                                           const StoredDiagnostic &InDiag)
+    : Level(InDiag.getLevel()), ID(InDiag.getID()),
+      Message(InDiag.getMessage()) {
+  const FullSourceLoc &FullLoc = InDiag.getLocation();
+  // This is not an invalid diagnostic; invalid SourceLocations are used to
+  // represent diagnostics without a specific SourceLocation.
+  if (FullLoc.isInvalid())
+    return;
+
+  const auto &SrcMgr = FullLoc.getManager();
+  FileKind = SrcMgr.getFileCharacteristic(static_cast<SourceLocation>(FullLoc));
+  const auto FileLoc = SrcMgr.getFileLoc(static_cast<SourceLocation>(FullLoc));
+  FileOffset = SrcMgr.getFileOffset(FileLoc);
+  Filename = SrcMgr.getFilename(FileLoc);
+  assert(!Filename.empty() && "diagnostic with location has no source file?");
+
+  Ranges.reserve(InDiag.getRanges().size());
+  for (const auto &Range : InDiag.getRanges())
+    Ranges.emplace_back(Range, SrcMgr, LangOpts);
+
+  FixIts.reserve(InDiag.getFixIts().size());
+  for (const auto &FixIt : InDiag.getFixIts())
+    FixIts.emplace_back(SrcMgr, LangOpts, FixIt);
+}
+
+StoredDiagnostic
+translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr,
+                        const StandaloneDiagnostic &StandaloneDiag,
+                        llvm::StringMap<SourceLocation> &SrcLocCache) {
+  const auto FileRef = FileMgr.getOptionalFileRef(StandaloneDiag.Filename);
+  if (!FileRef)
+    return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID,
+                            StandaloneDiag.Message);
+
+  // Try to get FileLoc from cache first
+  SourceLocation FileLoc;
+  auto It = SrcLocCache.find(StandaloneDiag.Filename);
+  if (It != SrcLocCache.end()) {
+    FileLoc = It->getValue();
+  }
+
+  // Cache miss - compute and cache the location
+  if (FileLoc.isInvalid()) {
+    const auto FileID =
+        SrcMgr.getOrCreateFileID(*FileRef, StandaloneDiag.FileKind);
+    FileLoc = SrcMgr.getLocForStartOfFile(FileID);
+
+    if (FileLoc.isInvalid())
+      return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID,
+                              StandaloneDiag.Message);
+
+    SrcLocCache[StandaloneDiag.Filename] = FileLoc;
+  }
+
+  const auto DiagLoc = FileLoc.getLocWithOffset(StandaloneDiag.FileOffset);
+  const FullSourceLoc Loc(DiagLoc, SrcMgr);
+
+  auto ConvertOffsetRange =
+      [&](const StandaloneDiagnostic::SourceOffsetRange &Range) {
+        return CharSourceRange(
+            SourceRange(FileLoc.getLocWithOffset(Range.Begin),
+                        FileLoc.getLocWithOffset(Range.End)),
+            /*IsTokenRange*/ false);
+      };
+
+  SmallVector<CharSourceRange, 4> TranslatedRanges;
+  TranslatedRanges.reserve(StandaloneDiag.Ranges.size());
+  transform(StandaloneDiag.Ranges, std::back_inserter(TranslatedRanges),
+            ConvertOffsetRange);
+
+  SmallVector<FixItHint, 2> TranslatedFixIts;
+  TranslatedFixIts.reserve(StandaloneDiag.FixIts.size());
+  for (const auto &FixIt : StandaloneDiag.FixIts) {
+    FixItHint TranslatedFixIt;
+    TranslatedFixIt.CodeToInsert = FixIt.CodeToInsert;
+    TranslatedFixIt.RemoveRange = ConvertOffsetRange(FixIt.RemoveRange);
+    TranslatedFixIt.InsertFromRange = ConvertOffsetRange(FixIt.InsertFromRange);
+    TranslatedFixIt.BeforePreviousInsertions = FixIt.BeforePreviousInsertions;
+    TranslatedFixIts.push_back(std::move(TranslatedFixIt));
+  }
+
+  return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID,
+                          StandaloneDiag.Message, Loc, TranslatedRanges,
+                          TranslatedFixIts);
+}
+
+} // namespace clang
diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt
index 37faa0302caaa..9a597146b2fc4 100644
--- a/clang/lib/Interpreter/CMakeLists.txt
+++ b/clang/lib/Interpreter/CMakeLists.txt
@@ -46,6 +46,7 @@ add_clang_library(clangInterpreter
   clangFrontend
   clangFrontendTool
   clangLex
+  clangOptions
   clangParse
   clangSema
   clangSerialization
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 7764fa7dc92b9..6cbc5e9910bcc 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -42,6 +42,7 @@
 #include "clang/Interpreter/Interpreter.h"
 #include "clang/Interpreter/Value.h"
 #include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Serialization/ObjectFilePCHContainerReader.h"
@@ -105,7 +106,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
     Clang->getHeaderSearchOpts().ResourceDir =
-        CompilerInvocation::GetResourcesPath(Argv[0], nullptr);
+        GetResourcesPath(Argv[0], nullptr);
 
   Clang->createVirtualFileSystem();
 
diff --git a/clang/lib/Options/OptionUtils.cpp b/clang/lib/Options/OptionUtils.cpp
index fcafd3c83c6b3..e5aefa012f679 100644
--- a/clang/lib/Options/OptionUtils.cpp
+++ b/clang/lib/Options/OptionUtils.cpp
@@ -9,7 +9,12 @@
 #include "clang/Options/OptionUtils.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
+#include "clang/Options/Options.h"
 #include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 
 using namespace clang;
 using namespace llvm::opt;
@@ -31,17 +36,211 @@ IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id,
 }
 } // namespace
 
-namespace clang {
-
-int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
-                       DiagnosticsEngine *Diags, unsigned Base) {
+int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
+                              DiagnosticsEngine *Diags, unsigned Base) {
   return getLastArgIntValueImpl<int>(Args, Id, Default, Diags, Base);
 }
 
-uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
-                               uint64_t Default, DiagnosticsEngine *Diags,
-                               unsigned Base) {
+uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
+                                      uint64_t Default,
+                                      DiagnosticsEngine *Diags, unsigned Base) {
   return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags, Base);
 }
 
-} // namespace clang
+StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,
+                                               const llvm::opt::ArgList &Args) {
+  const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ);
+  if (!A)
+    return "";
+
+  StringRef Value = A->getValue();
+  unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED;
+
+  // Only "none" and Integer values are accepted by
+  // -mprefer-vector-width=<value>.
+  if (Value != "none" && Value.getAsInteger(10, Width)) {
+    Diags.Report(clang::diag::err_drv_invalid_value)
+        << A->getOption().getName() << Value;
+    return "";
+  }
+
+  return Value;
+}
+
+// This is a helper function for validating the optional refinement step
+// parameter in reciprocal argument strings. Return false if there is an error
+// parsing the refinement step. Otherwise, return true and set the Position
+// of the refinement step in the input string.
+static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags,
+                              const Arg &A, size_t &Position) {
+  const char RefinementStepToken = ':';
+  Position = In.find(RefinementStepToken);
+  if (Position != StringRef::npos) {
+    StringRef Option = A.getOption().getName();
+    StringRef RefStep = In.substr(Position + 1);
+    // Allow exactly one numeric character for the additional refinement
+    // step parameter. This is reasonable for all currently-supported
+    // operations and architectures because we would expect that a larger value
+    // of refinement steps would cause the estimate "optimization" to
+    // under-perform the native operation. Also, if the estimate does not
+    // converge quickly, it probably will not ever converge, so further
+    // refinement steps will not produce a better answer.
+    if (RefStep.size() != 1) {
+      Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
+      return false;
+    }
+    char RefStepChar = RefStep[0];
+    if (RefStepChar < '0' || RefStepChar > '9') {
+      Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;
+      return false;
+    }
+  }
+  return true;
+}
+
+StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags,
+                                   const ArgList &Args) {
+  StringRef DisabledPrefixIn = "!";
+  StringRef DisabledPrefixOut = "!";
+  StringRef EnabledPrefixOut = "";
+  StringRef Out = "";
+
+  const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
+  if (!A)
+    return "";
+
+  const unsigned NumOptions = A->getNumValues();
+  if (NumOptions == 0) {
+    // No option is the same as "all".
+    return "all";
+  }
+
+  // Pass through "all", "none", or "default" with an optional refinement step.
+  if (NumOptions == 1) {
+    StringRef Val = A->getValue(0);
+    size_t RefStepLoc;
+    if (!getRefinementStep(Val, Diags, *A, RefStepLoc))
+      return "";
+    StringRef ValBase = Val.slice(0, RefStepLoc);
+    if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
+      return Val;
+    }
+  }
+
+  // Each reciprocal type may be enabled or disabled individually.
+  // Check each input value for validity, concatenate them all back together,
+  // and pass through.
+
+  llvm::StringMap<bool> OptionStrings;
+  OptionStrings.insert(std::make_pair("divd", false));
+  OptionStrings.insert(std::make_pair("divf", false));
+  OptionStrings.insert(std::make_pair("divh", false));
+  OptionStrings.insert(std::make_pair("vec-divd", false));
+  OptionStrings.insert(std::make_pair("vec-divf", false));
+  OptionStrings.insert(std::make_pair("vec-divh", false));
+  OptionStrings.insert(std::make_pair("sqrtd", false));
+  OptionStrings.insert(std::make_pair("sqrtf", false));
+  OptionStrings.insert(std::make_pair("sqrth", false));
+  OptionStrings.insert(std::make_pair("vec-sqrtd", false));
+  OptionStrings.insert(std::make_pair("vec-sqrtf", false));
+  OptionStrings.insert(std::make_pair("vec-sqrth", false));
+
+  for (unsigned i = 0; i != NumOptions; ++i) {
+    StringRef Val = A->getValue(i);
+
+    bool IsDisabled = Val.starts_with(DisabledPrefixIn);
+    // Ignore the disablement token for string matching.
+    if (IsDisabled)
+      Val = Val.substr(1);
+
+    size_t RefStep;
+    if (!getRefinementStep(Val, Diags, *A, RefStep))
+      return "";
+
+    StringRef ValBase = Val.slice(0, RefStep);
+    llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
+    if (OptionIter == OptionStrings.end()) {
+      // Try again specifying float suffix.
+      OptionIter = OptionStrings.find(ValBase.str() + 'f');
+      if (OptionIter == OptionStrings.end()) {
+        // The input name did not match any known option string.
+        Diags.Report(diag::err_drv_unknown_argument) << Val;
+        return "";
+      }
+      // The option was specified without a half or float or double suffix.
+      // Make sure that the double or half entry was not already specified.
+      // The float entry will be checked below.
+      if (OptionStrings[ValBase.str() + 'd'] ||
+          OptionStrings[ValBase.str() + 'h']) {
+        Diags.Report(diag::err_drv_invalid_value)
+            << A->getOption().getName() << Val;
+        return "";
+      }
+    }
+
+    if (OptionIter->second == true) {
+      // Duplicate option specified.
+      Diags.Report(diag::err_drv_invalid_value)
+          << A->getOption().getName() << Val;
+      return "";
+    }
+
+    // Mark the matched option as found. Do not allow duplicate specifiers.
+    OptionIter->second = true;
+
+    // If the precision was not specified, also mark the double and half entry
+    // as found.
+    if (ValBase.back() != 'f' && ValBase.back() != 'd' &&
+        ValBase.back() != 'h') {
+      OptionStrings[ValBase.str() + 'd'] = true;
+      OptionStrings[ValBase.str() + 'h'] = true;
+    }
+
+    // Build the output string.
+    StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
+    Out = Args.MakeArgString(Out + Prefix + Val);
+    if (i != NumOptions - 1)
+      Out = Args.MakeArgString(Out + ",");
+  }
+
+  return Out;
+}
+
+std::string clang::GetResourcesPath(StringRef BinaryPath) {
+  // Since the resource directory is embedded in the module hash, it's important
+  // that all places that need it call this function, so that they get the
+  // exact same string ("a/../b/" and "b/" get different hashes, for example).
+
+  // Dir is bin/ or lib/, depending on where BinaryPath is.
+  StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
+  SmallString<128> P(Dir);
+
+  StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR);
+  if (!ConfiguredResourceDir.empty()) {
+    // FIXME: We should fix the behavior of llvm::sys::path::append so we don't
+    // need to check for absolute paths here.
+    if (llvm::sys::path::is_absolute(ConfiguredResourceDir))
+      P = ConfiguredResourceDir;
+    else
+      llvm::sys::path::append(P, ConfiguredResourceDir);
+  } else {
+    // On Windows, libclang.dll is in bin/.
+    // On non-Windows, libclang.so/.dylib is in lib/.
+    // With a static-library build of libclang, LibClangPath will contain the
+    // path of the embedding binary, which for LLVM binaries will be in bin/.
+    // ../lib gets us to lib/ in both cases.
+    P = llvm::sys::path::parent_path(Dir);
+    // This search path is also created in the COFF driver of lld, so any
+    // changes here also needs to happen in lld/COFF/Driver.cpp
+    llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
+                            CLANG_VERSION_MAJOR_STRING);
+  }
+
+  return std::string(P);
+}
+
+std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) {
+  const std::string ClangExecutable =
+      llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
+  return GetResourcesPath(ClangExecutable);
+}
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 9bae12454d2dc..1d55f615de8a9 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -31,6 +31,7 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Options/OptionUtils.h"
 #include "clang/Options/Options.h"
 #include "clang/Tooling/ArgumentsAdjusters.h"
 #include "clang/Tooling/CompilationDatabase.h"
@@ -510,8 +511,7 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0,
 
   // If there's no override in place add our resource dir.
   Args = getInsertArgumentAdjuster(
-      ("-resource-dir=" + CompilerInvocation::GetResourcesPath(Argv0, MainAddr))
-          .c_str())(Args, "");
+      ("-resource-dir=" + GetResourcesPath(Argv0, MainAddr)).c_str())(Args, "");
 }
 
 int ClangTool::run(ToolAction *Action) {
diff --git a/clang/tools/c-index-test/CMakeLists.txt b/clang/tools/c-index-test/CMakeLists.txt
index 24e7c9692ca56..41e80e66ffa7a 100644
--- a/clang/tools/c-index-test/CMakeLists.txt
+++ b/clang/tools/c-index-test/CMakeLists.txt
@@ -27,6 +27,7 @@ else()
     libclang
     clangAST
     clangBasic
+    clangDriver
     clangFrontend
     clangIndex
     clangSerialization
diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp
index 5a3086a7fc08f..c67479fd130ca 100644
--- a/clang/tools/c-index-test/core_main.cpp
+++ b/clang/tools/c-index-test/core_main.cpp
@@ -8,6 +8,7 @@
 
 #include "clang/AST/Mangle.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
diff --git a/clang/tools/diagtool/CMakeLists.txt b/clang/tools/diagtool/CMakeLists.txt
index b49619c075c73..09b2a81790f87 100644
--- a/clang/tools/diagtool/CMakeLists.txt
+++ b/clang/tools/diagtool/CMakeLists.txt
@@ -15,5 +15,6 @@ add_clang_tool(diagtool
 clang_target_link_libraries(diagtool
   PRIVATE
   clangBasic
+  clangDriver
   clangFrontend
   )
diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp
index bea0288c09358..5b25e656dafa4 100644
--- a/clang/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp
@@ -9,6 +9,7 @@
 #include "DiagTool.h"
 #include "DiagnosticNames.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/TextDiagnosticBuffer.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 300d59df1bf7b..cc757039cafd0 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -17,6 +17,7 @@
 #include "clang/Basic/TargetOptions.h"
 #include "clang/CodeGen/ObjectFilePCHContainerWriter.h"
 #include "clang/Config/config.h"
+#include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -269,7 +270,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
     Clang->getHeaderSearchOpts().ResourceDir =
-        CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+        GetResourcesPath(Argv0, MainAddr);
 
   /// Create the actual file system.
   Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer);
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index f4d6fa72a1dfe..32e84248c1b27 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -38,6 +38,7 @@
 #include "clang/Basic/Stack.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/Version.h"
+#include "clang/Driver/CreateASTUnitFromArgs.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Index/CommentToXML.h"
@@ -4361,7 +4362,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
   LibclangInvocationReporter InvocationReporter(
       *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation,
       options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files);
-  std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromCommandLine(
+  std::unique_ptr<ASTUnit> Unit = CreateASTUnitFromCommandLine(
       Args->data(), Args->data() + Args->size(),
       CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
       CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(),
diff --git a/clang/tools/libclang/CIndexer.cpp b/clang/tools/libclang/CIndexer.cpp
index 11d9312b64849..853a936b43e37 100644
--- a/clang/tools/libclang/CIndexer.cpp
+++ b/clang/tools/libclang/CIndexer.cpp
@@ -16,6 +16,7 @@
 #include "clang/Basic/Version.h"
 #include "clang/Config/config.h"
 #include "clang/Driver/Driver.h"
+#include "clang/Options/OptionUtils.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/FileSystem.h"
@@ -137,7 +138,7 @@ const std::string &CIndexer::getClangResourcesPath() {
 #endif
 
   // Cache our result.
-  ResourcesPath = driver::Driver::GetResourcesPath(LibClangPath);
+  ResourcesPath = GetResourcesPath(LibClangPath);
   return ResourcesPath;
 }
 
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index e0ff7605b68b8..b0105f5a5f79f 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -65,6 +65,7 @@ set(LIBS
   clangFrontend
   clangIndex
   clangLex
+  clangOptions
   clangRewrite
   clangSema
   clangSerialization
diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp
index c142f142d5071..75323d70afcfe 100644
--- a/clang/tools/libclang/Indexing.cpp
+++ b/clang/tools/libclang/Indexing.cpp
@@ -15,6 +15,7 @@
 #include "CXString.h"
 #include "CXTranslationUnit.h"
 #include "clang/AST/ASTConsumer.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp
index e0454f190b35a..130da620b40b5 100644
--- a/clang/unittests/Driver/DXCModeTest.cpp
+++ b/clang/unittests/Driver/DXCModeTest.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/TargetOptions.h"
 #include "clang/Driver/Compilation.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/ToolChain.h"
 #include "clang/Frontend/CompilerInstance.h"
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index afa17ff219be2..8f533790ec501 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -17,6 +17,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
 #include "clang/Driver/Compilation.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "llvm/ADT/ArrayRef.h"
diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp
index dfdbe90e72f1f..bf9e4e184b5db 100644
--- a/clang/unittests/Frontend/ASTUnitTest.cpp
+++ b/clang/unittests/Frontend/ASTUnitTest.cpp
@@ -9,6 +9,8 @@
 #include <fstream>
 
 #include "clang/Basic/FileManager.h"
+#include "clang/Driver/CreateASTUnitFromArgs.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -173,7 +175,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) {
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
-  std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
+  std::unique_ptr<ASTUnit> AST = CreateASTUnitFromCommandLine(
       &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
       false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
       false, SkipFunctionBodiesScope::None, false, true, false, false,
@@ -201,7 +203,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) {
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
-  std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
+  std::unique_ptr<ASTUnit> AST = CreateASTUnitFromCommandLine(
       &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
       false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
       false, SkipFunctionBodiesScope::None, false, true, false, false,
diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp
index cd3fefa1ea994..39d35b48f394a 100644
--- a/clang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -8,6 +8,7 @@
 
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp
index fc411e4af705f..a82733d57714a 100644
--- a/clang/unittests/Frontend/UtilsTest.cpp
+++ b/clang/unittests/Frontend/UtilsTest.cpp
@@ -9,6 +9,7 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/TargetOptions.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Lex/PreprocessorOptions.h"
diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt
index b61ed8c457635..188f6135a60ac 100644
--- a/clang/unittests/Sema/CMakeLists.txt
+++ b/clang/unittests/Sema/CMakeLists.txt
@@ -13,6 +13,7 @@ add_distinct_clang_unittest(SemaTests
   clangAST
   clangASTMatchers
   clangBasic
+  clangDriver
   clangFrontend
   clangParse
   clangSema
diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
index e565372698e5e..3944269eff502 100644
--- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp
+++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
@@ -10,6 +10,7 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
index edf33ae04230b..b76dcfec96063 100644
--- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
+++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
@@ -9,6 +9,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
index d7b55491fddac..f55925aeae1f2 100644
--- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
+++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp
index e9b8da3dba6af..df26e54588b9e 100644
--- a/clang/unittests/Serialization/ModuleCacheTest.cpp
+++ b/clang/unittests/Serialization/ModuleCacheTest.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/FileManager.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp
index 01bb6999a7c90..444a082bba907 100644
--- a/clang/unittests/Serialization/NoCommentsTest.cpp
+++ b/clang/unittests/Serialization/NoCommentsTest.cpp
@@ -9,6 +9,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
index 55ee72875ead2..b826f20ce4d70 100644
--- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
+++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
index 743f851fc5fe1..2be01def49809 100644
--- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
+++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
@@ -9,6 +9,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp
index 47184cbf5d768..468ca5ddd2c75 100644
--- a/clang/unittests/Tooling/Syntax/TokensTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp
@@ -20,6 +20,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TokenKinds.def"
 #include "clang/Basic/TokenKinds.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/Utils.h"
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
index b2be64fc08f3d..dad75854240ef 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
@@ -13,6 +13,7 @@
 #include "TreeTestBase.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendAction.h"
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index bb0b4a39cec9b..fb74b3dcb280e 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -75,7 +75,6 @@ add_flang_library(flangFrontend
 
   CLANG_LIBS
   clangBasic
-  clangDriver
   clangOptions
 )
 
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 0c32f3914e04b..b6c4e6303cdac 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -325,10 +325,9 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
   for (auto *a : args.filtered(clang::options::OPT_fpass_plugin_EQ))
     opts.LLVMPassPlugins.push_back(a->getValue());
 
-  opts.Reciprocals = clang::driver::tools::parseMRecipOption(diags, args);
+  opts.Reciprocals = clang::parseMRecipOption(diags, args);
 
-  opts.PreferVectorWidth =
-      clang::driver::tools::parseMPreferVectorWidthOption(diags, args);
+  opts.PreferVectorWidth = clang::parseMPreferVectorWidthOption(diags, args);
 
   // -fembed-offload-object option
   for (auto *a : args.filtered(clang::options::OPT_fembed_offload_object_EQ))
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 30bca639060e6..7f880d223d6c3 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -60,6 +60,7 @@
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-private-enumerations.h"
 
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
index 01d588ff6a78b..759a7c4dd14fb 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang
   CLANG_LIBS
     clangAST
     clangCodeGen
-    clangDriver
     clangEdit
     clangFrontend
     clangLex
+    clangOptions
     clangParse
     clangRewrite
     clangRewriteFrontend
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
index 6de851081598f..660a21e3c6a8d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
@@ -10,7 +10,7 @@
 
 #include "clang/Basic/Version.h"
 #include "clang/Config/config.h"
-#include "clang/Driver/Driver.h"
+#include "clang/Options/OptionUtils.h"
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
@@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
   std::string raw_path = lldb_shlib_spec.GetPath();
   llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
   static const std::string clang_resource_path =
-      clang::driver::Driver::GetResourcesPath("bin/lldb");
+      clang::GetResourcesPath("bin/lldb");
 
   static const llvm::StringRef kResourceDirSuffixes[] = {
       // LLVM.org's build of LLDB uses the clang resource directory placed
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index e37c84efefdc9..ce8dc50b84a31 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -10,6 +10,7 @@
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
diff --git a/lldb/unittests/Expression/ClangParserTest.cpp b/lldb/unittests/Expression/ClangParserTest.cpp
index fab4487c73719..c949026e87cd8 100644
--- a/lldb/unittests/Expression/ClangParserTest.cpp
+++ b/lldb/unittests/Expression/ClangParserTest.cpp
@@ -8,7 +8,7 @@
 
 #include "clang/Basic/Version.h"
 #include "clang/Config/config.h"
-#include "clang/Driver/Driver.h"
+#include "clang/Options/OptionUtils.h"
 
 #include "Plugins/ExpressionParser/Clang/ClangHost.h"
 #include "TestingSupport/SubsystemRAII.h"
@@ -43,7 +43,7 @@ TEST_F(ClangHostTest, ComputeClangResourceDirectory) {
   std::string path_to_liblldb = "C:\\foo\\bar\\lib\\";
 #endif
   std::string path_to_clang_dir =
-      clang::driver::Driver::GetResourcesPath(path_to_liblldb + "liblldb");
+      clang::GetResourcesPath(path_to_liblldb + "liblldb");
   llvm::SmallString<256> path_to_clang_lib_dir_real;
   llvm::sys::fs::real_path(path_to_clang_dir, path_to_clang_lib_dir_real);
 
diff --git a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
index 4ac3e75b9c1ce..020b2aa68a357 100644
--- a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
@@ -1563,6 +1563,7 @@ cc_library(
         ":basic",
         ":config",
         ":driver_options_inc_gen",
+        ":frontend",
         ":lex",
         ":options",
         ":parse",
@@ -1718,7 +1719,6 @@ cc_library(
         ":ast",
         ":basic",
         ":config",
-        ":driver",
         ":driver_options_inc_gen",
         ":edit",
         ":lex",

>From c7f461cbd06e4a15f4222dc05ccea26192c4cd8f Mon Sep 17 00:00:00 2001
From: Naveen Seth Hanig <naveen.hanig at outlook.com>
Date: Wed, 26 Nov 2025 04:56:41 +0100
Subject: [PATCH 2/2] Remove Bazel changes

Because of the failing Bazel build, this removes the corresponding
Bazel related changes for now.
---
 utils/bazel/llvm-project-overlay/clang/BUILD.bazel | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
index 020b2aa68a357..4ac3e75b9c1ce 100644
--- a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel
@@ -1563,7 +1563,6 @@ cc_library(
         ":basic",
         ":config",
         ":driver_options_inc_gen",
-        ":frontend",
         ":lex",
         ":options",
         ":parse",
@@ -1719,6 +1718,7 @@ cc_library(
         ":ast",
         ":basic",
         ":config",
+        ":driver",
         ":driver_options_inc_gen",
         ":edit",
         ":lex",



More information about the lldb-commits mailing list