summaryrefslogtreecommitdiff
path: root/gnu/llvm/clang/tools/driver
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/clang/tools/driver')
-rw-r--r--gnu/llvm/clang/tools/driver/CMakeLists.txt124
-rw-r--r--gnu/llvm/clang/tools/driver/Info.plist.in18
-rw-r--r--gnu/llvm/clang/tools/driver/cc1_main.cpp277
-rw-r--r--gnu/llvm/clang/tools/driver/cc1as_main.cpp617
-rw-r--r--gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp195
-rw-r--r--gnu/llvm/clang/tools/driver/driver.cpp557
6 files changed, 1788 insertions, 0 deletions
diff --git a/gnu/llvm/clang/tools/driver/CMakeLists.txt b/gnu/llvm/clang/tools/driver/CMakeLists.txt
new file mode 100644
index 00000000000..2b783cff095
--- /dev/null
+++ b/gnu/llvm/clang/tools/driver/CMakeLists.txt
@@ -0,0 +1,124 @@
+set( LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Analysis
+ CodeGen
+ Core
+ IPO
+ AggressiveInstCombine
+ InstCombine
+ Instrumentation
+ MC
+ MCParser
+ ObjCARCOpts
+ Option
+ ScalarOpts
+ Support
+ TransformUtils
+ Vectorize
+ )
+
+option(CLANG_PLUGIN_SUPPORT "Build clang with plugin support" ON)
+
+# Support plugins.
+if(CLANG_PLUGIN_SUPPORT)
+ set(support_plugins SUPPORT_PLUGINS)
+endif()
+
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_clang_tool(clang
+ driver.cpp
+ cc1_main.cpp
+ cc1as_main.cpp
+ cc1gen_reproducer_main.cpp
+
+ DEPENDS
+ ${tablegen_deps}
+ ${support_plugins}
+ )
+
+clang_target_link_libraries(clang
+ PRIVATE
+ clangBasic
+ clangCodeGen
+ clangDriver
+ clangFrontend
+ clangFrontendTool
+ clangSerialization
+ )
+
+if(WIN32 AND NOT CYGWIN)
+ # Prevent versioning if the buildhost is targeting for Win32.
+else()
+ set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+endif()
+
+# Support plugins.
+if(CLANG_PLUGIN_SUPPORT)
+ export_executable_symbols(clang)
+endif()
+
+add_dependencies(clang clang-resource-headers)
+
+if(NOT CLANG_LINKS_TO_CREATE)
+ set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp)
+endif()
+
+foreach(link ${CLANG_LINKS_TO_CREATE})
+ add_clang_symlink(${link} clang)
+endforeach()
+
+# Configure plist creation for OS X.
+set (TOOL_INFO_PLIST "Info.plist" CACHE STRING "Plist name")
+if (APPLE)
+ if (CLANG_VENDOR)
+ set(TOOL_INFO_NAME "${CLANG_VENDOR} clang")
+ else()
+ set(TOOL_INFO_NAME "clang")
+ endif()
+
+ set(TOOL_INFO_UTI "${CLANG_VENDOR_UTI}")
+ set(TOOL_INFO_VERSION "${CLANG_VERSION}")
+ set(TOOL_INFO_BUILD_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+
+ set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}")
+ target_link_libraries(clang
+ PRIVATE
+ "-Wl,-sectcreate,__TEXT,__info_plist,${TOOL_INFO_PLIST_OUT}")
+ configure_file("${TOOL_INFO_PLIST}.in" "${TOOL_INFO_PLIST_OUT}" @ONLY)
+
+ set(TOOL_INFO_UTI)
+ set(TOOL_INFO_NAME)
+ set(TOOL_INFO_VERSION)
+ set(TOOL_INFO_BUILD_VERSION)
+endif()
+
+if(CLANG_ORDER_FILE AND
+ (LLVM_LINKER_IS_LD64 OR LLVM_LINKER_IS_GOLD OR LLVM_LINKER_IS_LLD))
+ include(CheckLinkerFlag)
+
+ if (LLVM_LINKER_IS_LD64)
+ set(LINKER_ORDER_FILE_OPTION "-Wl,-order_file,${CLANG_ORDER_FILE}")
+ elseif (LLVM_LINKER_IS_GOLD)
+ set(LINKER_ORDER_FILE_OPTION "-Wl,--section-ordering-file,${CLANG_ORDER_FILE}")
+ elseif (LLVM_LINKER_IS_LLD)
+ set(LINKER_ORDER_FILE_OPTION "-Wl,--symbol-ordering-file,${CLANG_ORDER_FILE}")
+ endif()
+
+ # This is a test to ensure the actual order file works with the linker.
+ check_linker_flag(${LINKER_ORDER_FILE_OPTION} LINKER_ORDER_FILE_WORKS)
+
+ # Passing an empty order file disables some linker layout optimizations.
+ # To work around this and enable workflows for re-linking when the order file
+ # changes we check during configuration if the file is empty, and make it a
+ # configuration dependency.
+ file(READ ${CLANG_ORDER_FILE} ORDER_FILE LIMIT 20)
+ if("${ORDER_FILE}" STREQUAL "\n")
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CLANG_ORDER_FILE})
+ elseif(LINKER_ORDER_FILE_WORKS)
+ target_link_libraries(clang PRIVATE ${LINKER_ORDER_FILE_OPTION})
+ set_target_properties(clang PROPERTIES LINK_DEPENDS ${CLANG_ORDER_FILE})
+ endif()
+endif()
diff --git a/gnu/llvm/clang/tools/driver/Info.plist.in b/gnu/llvm/clang/tools/driver/Info.plist.in
new file mode 100644
index 00000000000..c2b157021df
--- /dev/null
+++ b/gnu/llvm/clang/tools/driver/Info.plist.in
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleIdentifier</key>
+ <string>@TOOL_INFO_UTI@</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>@TOOL_INFO_NAME@</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@TOOL_INFO_VERSION@</string>
+ <key>CFBundleVersion</key>
+ <string>@TOOL_INFO_BUILD_VERSION@</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+</dict>
+</plist>
diff --git a/gnu/llvm/clang/tools/driver/cc1_main.cpp b/gnu/llvm/clang/tools/driver/cc1_main.cpp
new file mode 100644
index 00000000000..6d1a67f2a4f
--- /dev/null
+++ b/gnu/llvm/clang/tools/driver/cc1_main.cpp
@@ -0,0 +1,277 @@
+//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1 functionality, which implements the
+// core compiler functionality along with a number of additional tools for
+// demonstration and testing purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Stack.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/FrontendTool/Utils.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/LinkAllPasses.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Support/BuryPointer.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TimeProfiler.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include <cstdio>
+
+#ifdef CLANG_HAVE_RLIMITS
+#include <sys/resource.h>
+#endif
+
+using namespace clang;
+using namespace llvm::opt;
+
+//===----------------------------------------------------------------------===//
+// Main driver
+//===----------------------------------------------------------------------===//
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message,
+ bool GenCrashDiag) {
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // Run the interrupt handlers to make sure any special cleanups get done, in
+ // particular that we remove files registered with RemoveFileOnSignal.
+ llvm::sys::RunInterruptHandlers();
+
+ // We cannot recover from llvm errors. When reporting a fatal error, exit
+ // with status 70 to generate crash diagnostics. For BSD systems this is
+ // defined as an internal software error. Otherwise, exit with status 1.
+ llvm::sys::Process::Exit(GenCrashDiag ? 70 : 1);
+}
+
+#ifdef CLANG_HAVE_RLIMITS
+#if defined(__linux__) && defined(__PIE__)
+static size_t getCurrentStackAllocation() {
+ // If we can't compute the current stack usage, allow for 512K of command
+ // line arguments and environment.
+ size_t Usage = 512 * 1024;
+ if (FILE *StatFile = fopen("/proc/self/stat", "r")) {
+ // We assume that the stack extends from its current address to the end of
+ // the environment space. In reality, there is another string literal (the
+ // program name) after the environment, but this is close enough (we only
+ // need to be within 100K or so).
+ unsigned long StackPtr, EnvEnd;
+ // Disable silly GCC -Wformat warning that complains about length
+ // modifiers on ignored format specifiers. We want to retain these
+ // for documentation purposes even though they have no effect.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#endif
+ if (fscanf(StatFile,
+ "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu "
+ "%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu "
+ "%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d "
+ "%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d",
+ &StackPtr, &EnvEnd) == 2) {
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+ Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd;
+ }
+ fclose(StatFile);
+ }
+ return Usage;
+}
+
+#include <alloca.h>
+
+LLVM_ATTRIBUTE_NOINLINE
+static void ensureStackAddressSpace() {
+ // Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary
+ // relatively close to the stack (they are only guaranteed to be 128MiB
+ // apart). This results in crashes if we happen to heap-allocate more than
+ // 128MiB before we reach our stack high-water mark.
+ //
+ // To avoid these crashes, ensure that we have sufficient virtual memory
+ // pages allocated before we start running.
+ size_t Curr = getCurrentStackAllocation();
+ const int kTargetStack = DesiredStackSize - 256 * 1024;
+ if (Curr < kTargetStack) {
+ volatile char *volatile Alloc =
+ static_cast<volatile char *>(alloca(kTargetStack - Curr));
+ Alloc[0] = 0;
+ Alloc[kTargetStack - Curr - 1] = 0;
+ }
+}
+#else
+static void ensureStackAddressSpace() {}
+#endif
+
+/// Attempt to ensure that we have at least 8MiB of usable stack space.
+static void ensureSufficientStack() {
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_STACK, &rlim) != 0)
+ return;
+
+ // Increase the soft stack limit to our desired level, if necessary and
+ // possible.
+ if (rlim.rlim_cur != RLIM_INFINITY &&
+ rlim.rlim_cur < rlim_t(DesiredStackSize)) {
+ // Try to allocate sufficient stack.
+ if (rlim.rlim_max == RLIM_INFINITY ||
+ rlim.rlim_max >= rlim_t(DesiredStackSize))
+ rlim.rlim_cur = DesiredStackSize;
+ else if (rlim.rlim_cur == rlim.rlim_max)
+ return;
+ else
+ rlim.rlim_cur = rlim.rlim_max;
+
+ if (setrlimit(RLIMIT_STACK, &rlim) != 0 ||
+ rlim.rlim_cur != DesiredStackSize)
+ return;
+ }
+
+ // We should now have a stack of size at least DesiredStackSize. Ensure
+ // that we can actually use that much, if necessary.
+ ensureStackAddressSpace();
+}
+#else
+static void ensureSufficientStack() {}
+#endif
+
+/// Print supported cpus of the given target.
+static int PrintSupportedCPUs(std::string TargetStr) {
+ std::string Error;
+ const llvm::Target *TheTarget =
+ llvm::TargetRegistry::lookupTarget(TargetStr, Error);
+ if (!TheTarget) {
+ llvm::errs() << Error;
+ return 1;
+ }
+
+ // the target machine will handle the mcpu printing
+ llvm::TargetOptions Options;
+ std::unique_ptr<llvm::TargetMachine> TheTargetMachine(
+ TheTarget->createTargetMachine(TargetStr, "", "+cpuHelp", Options, None));
+ return 0;
+}
+
+int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
+ ensureSufficientStack();
+
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
+ // Register the support for object-file-wrapped Clang modules.
+ auto PCHOps = Clang->getPCHContainerOperations();
+ PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
+ PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
+
+ // Initialize targets first, so that --version shows registered targets.
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+
+ // Buffer diagnostics from argument parsing so that we can output them using a
+ // well formed diagnostic object.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+ bool Success =
+ CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv, Diags);
+
+ if (Clang->getFrontendOpts().TimeTrace) {
+ llvm::timeTraceProfilerInitialize(
+ Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
+ }
+ // --print-supported-cpus takes priority over the actual compilation.
+ if (Clang->getFrontendOpts().PrintSupportedCPUs)
+ return PrintSupportedCPUs(Clang->getTargetOpts().Triple);
+
+ // Infer the builtin include path if unspecified.
+ if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
+ Clang->getHeaderSearchOpts().ResourceDir.empty())
+ Clang->getHeaderSearchOpts().ResourceDir =
+ CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+
+ // Create the actual diagnostics engine.
+ Clang->createDiagnostics();
+ if (!Clang->hasDiagnostics())
+ return 1;
+
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ llvm::install_fatal_error_handler(LLVMErrorHandler,
+ static_cast<void*>(&Clang->getDiagnostics()));
+
+ DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
+ if (!Success)
+ return 1;
+
+ // Execute the frontend actions.
+ {
+ llvm::TimeTraceScope TimeScope("ExecuteCompiler");
+ Success = ExecuteCompilerInvocation(Clang.get());
+ }
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now. This happens in -disable-free mode.
+ llvm::TimerGroup::printAll(llvm::errs());
+ llvm::TimerGroup::clearAll();
+
+ if (llvm::timeTraceProfilerEnabled()) {
+ SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
+ llvm::sys::path::replace_extension(Path, "json");
+ if (auto profilerOutput =
+ Clang->createOutputFile(Path.str(),
+ /*Binary=*/false,
+ /*RemoveFileOnSignal=*/false, "",
+ /*Extension=*/"json",
+ /*useTemporary=*/false)) {
+
+ llvm::timeTraceProfilerWrite(*profilerOutput);
+ // FIXME(ibiryukov): make profilerOutput flush in destructor instead.
+ profilerOutput->flush();
+ llvm::timeTraceProfilerCleanup();
+ }
+ }
+
+ // Our error handler depends on the Diagnostics object, which we're
+ // potentially about to delete. Uninstall the handler now so that any
+ // later errors use the default handling behavior instead.
+ llvm::remove_fatal_error_handler();
+
+ // When running with -disable-free, don't do any destruction or shutdown.
+ if (Clang->getFrontendOpts().DisableFree) {
+ llvm::BuryPointer(std::move(Clang));
+ return !Success;
+ }
+
+ return !Success;
+}
diff --git a/gnu/llvm/clang/tools/driver/cc1as_main.cpp b/gnu/llvm/clang/tools/driver/cc1as_main.cpp
new file mode 100644
index 00000000000..e1041f91bfd
--- /dev/null
+++ b/gnu/llvm/clang/tools/driver/cc1as_main.cpp
@@ -0,0 +1,617 @@
+//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1as functionality, which implements
+// the direct interface to the LLVM MC based assembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <system_error>
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::options;
+using namespace llvm;
+using namespace llvm::opt;
+
+namespace {
+
+/// Helper class for representing a single invocation of the assembler.
+struct AssemblerInvocation {
+ /// @name Target Options
+ /// @{
+
+ /// The name of the target triple to assemble for.
+ std::string Triple;
+
+ /// If given, the name of the target CPU to determine which instructions
+ /// are legal.
+ std::string CPU;
+
+ /// The list of target specific features to enable or disable -- this should
+ /// be a list of strings starting with '+' or '-'.
+ std::vector<std::string> Features;
+
+ /// The list of symbol definitions.
+ std::vector<std::string> SymbolDefs;
+
+ /// @}
+ /// @name Language Options
+ /// @{
+
+ std::vector<std::string> IncludePaths;
+ unsigned NoInitialTextSection : 1;
+ unsigned SaveTemporaryLabels : 1;
+ unsigned GenDwarfForAssembly : 1;
+ unsigned RelaxELFRelocations : 1;
+ unsigned DwarfVersion;
+ std::string DwarfDebugFlags;
+ std::string DwarfDebugProducer;
+ std::string DebugCompilationDir;
+ std::map<const std::string, const std::string> DebugPrefixMap;
+ llvm::DebugCompressionType CompressDebugSections =
+ llvm::DebugCompressionType::None;
+ std::string MainFileName;
+ std::string SplitDwarfOutput;
+
+ /// @}
+ /// @name Frontend Options
+ /// @{
+
+ std::string InputFile;
+ std::vector<std::string> LLVMArgs;
+ std::string OutputPath;
+ enum FileType {
+ FT_Asm, ///< Assembly (.s) output, transliterate mode.
+ FT_Null, ///< No output, for timing purposes.
+ FT_Obj ///< Object file output.
+ };
+ FileType OutputType;
+ unsigned ShowHelp : 1;
+ unsigned ShowVersion : 1;
+
+ /// @}
+ /// @name Transliterate Options
+ /// @{
+
+ unsigned OutputAsmVariant;
+ unsigned ShowEncoding : 1;
+ unsigned ShowInst : 1;
+
+ /// @}
+ /// @name Assembler Options
+ /// @{
+
+ unsigned RelaxAll : 1;
+ unsigned NoExecStack : 1;
+ unsigned FatalWarnings : 1;
+ unsigned NoWarn : 1;
+ unsigned IncrementalLinkerCompatible : 1;
+ unsigned EmbedBitcode : 1;
+
+ /// The name of the relocation model to use.
+ std::string RelocationModel;
+
+ /// The ABI targeted by the backend. Specified using -target-abi. Empty
+ /// otherwise.
+ std::string TargetABI;
+
+ /// @}
+
+public:
+ AssemblerInvocation() {
+ Triple = "";
+ NoInitialTextSection = 0;
+ InputFile = "-";
+ OutputPath = "-";
+ OutputType = FT_Asm;
+ OutputAsmVariant = 0;
+ ShowInst = 0;
+ ShowEncoding = 0;
+ RelaxAll = 0;
+ NoExecStack = 0;
+ FatalWarnings = 0;
+ NoWarn = 0;
+ IncrementalLinkerCompatible = 0;
+ DwarfVersion = 0;
+ EmbedBitcode = 0;
+ }
+
+ static bool CreateFromArgs(AssemblerInvocation &Res,
+ ArrayRef<const char *> Argv,
+ DiagnosticsEngine &Diags);
+};
+
+}
+
+bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
+ ArrayRef<const char *> Argv,
+ DiagnosticsEngine &Diags) {
+ bool Success = true;
+
+ // Parse the arguments.
+ const OptTable &OptTbl = getDriverOptTable();
+
+ const unsigned IncludedFlagsBitmask = options::CC1AsOption;
+ unsigned MissingArgIndex, MissingArgCount;
+ InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
+ IncludedFlagsBitmask);
+
+ // Check for missing argument error.
+ if (MissingArgCount) {
+ Diags.Report(diag::err_drv_missing_argument)
+ << Args.getArgString(MissingArgIndex) << MissingArgCount;
+ Success = false;
+ }
+
+ // Issue errors on unknown arguments.
+ for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
+ auto ArgString = A->getAsString(Args);
+ std::string Nearest;
+ if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
+ Diags.Report(diag::err_drv_unknown_argument) << ArgString;
+ else
+ Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
+ << ArgString << Nearest;
+ Success = false;
+ }
+
+ // Construct the invocation.
+
+ // Target Options
+ Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
+ Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
+ Opts.Features = Args.getAllArgValues(OPT_target_feature);
+
+ // Use the default target triple if unspecified.
+ if (Opts.Triple.empty())
+ Opts.Triple = llvm::sys::getDefaultTargetTriple();
+
+ // Language Options
+ Opts.IncludePaths = Args.getAllArgValues(OPT_I);
+ Opts.NoInitialTextSection = Args.hasArg(OPT_n);
+ Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
+ // Any DebugInfoKind implies GenDwarfForAssembly.
+ Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
+
+ if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
+ OPT_compress_debug_sections_EQ)) {
+ if (A->getOption().getID() == OPT_compress_debug_sections) {
+ // TODO: be more clever about the compression type auto-detection
+ Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
+ } else {
+ Opts.CompressDebugSections =
+ llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+ .Case("none", llvm::DebugCompressionType::None)
+ .Case("zlib", llvm::DebugCompressionType::Z)
+ .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Default(llvm::DebugCompressionType::None);
+ }
+ }
+
+ Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
+ Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
+ Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
+ Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer);
+ Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
+ Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
+
+ for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
+ Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
+
+ // Frontend Options
+ if (Args.hasArg(OPT_INPUT)) {
+ bool First = true;
+ for (const Arg *A : Args.filtered(OPT_INPUT)) {
+ if (First) {
+ Opts.InputFile = A->getValue();
+ First = false;
+ } else {
+ Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
+ Success = false;
+ }
+ }
+ }
+ Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
+ Opts.OutputPath = Args.getLastArgValue(OPT_o);
+ Opts.SplitDwarfOutput = Args.getLastArgValue(OPT_split_dwarf_output);
+ if (Arg *A = Args.getLastArg(OPT_filetype)) {
+ StringRef Name = A->getValue();
+ unsigned OutputType = StringSwitch<unsigned>(Name)
+ .Case("asm", FT_Asm)
+ .Case("null", FT_Null)
+ .Case("obj", FT_Obj)
+ .Default(~0U);
+ if (OutputType == ~0U) {
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ Success = false;
+ } else
+ Opts.OutputType = FileType(OutputType);
+ }
+ Opts.ShowHelp = Args.hasArg(OPT_help);
+ Opts.ShowVersion = Args.hasArg(OPT_version);
+
+ // Transliterate Options
+ Opts.OutputAsmVariant =
+ getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
+ Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
+ Opts.ShowInst = Args.hasArg(OPT_show_inst);
+
+ // Assemble Options
+ Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
+ Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
+ Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
+ Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
+ Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+ Opts.TargetABI = Args.getLastArgValue(OPT_target_abi);
+ Opts.IncrementalLinkerCompatible =
+ Args.hasArg(OPT_mincremental_linker_compatible);
+ Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
+
+ // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag.
+ // EmbedBitcode behaves the same for all embed options for assembly files.
+ if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) {
+ Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("all", 1)
+ .Case("bitcode", 1)
+ .Case("marker", 1)
+ .Default(0);
+ }
+
+ return Success;
+}
+
+static std::unique_ptr<raw_fd_ostream>
+getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
+ // Make sure that the Out file gets unlinked from the disk if we get a
+ // SIGINT.
+ if (Path != "-")
+ sys::RemoveFileOnSignal(Path);
+
+ std::error_code EC;
+ auto Out = std::make_unique<raw_fd_ostream>(
+ Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
+ if (EC) {
+ Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
+ return nullptr;
+ }
+
+ return Out;
+}
+
+static bool ExecuteAssembler(AssemblerInvocation &Opts,
+ DiagnosticsEngine &Diags) {
+ // Get the target specific parser.
+ std::string Error;
+ const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
+ if (!TheTarget)
+ return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+ MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
+
+ if (std::error_code EC = Buffer.getError()) {
+ Error = EC.message();
+ return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
+ }
+
+ SourceMgr SrcMgr;
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ unsigned BufferIndex = SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
+
+ // Record the location of the include directories so that the lexer can find
+ // it later.
+ SrcMgr.setIncludeDirs(Opts.IncludePaths);
+
+ std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
+ assert(MRI && "Unable to create target register info!");
+
+ MCTargetOptions MCOptions;
+ std::unique_ptr<MCAsmInfo> MAI(
+ TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
+ assert(MAI && "Unable to create target asm info!");
+
+ // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
+ // may be created with a combination of default and explicit settings.
+ MAI->setCompressDebugSections(Opts.CompressDebugSections);
+
+ MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
+
+ bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
+ if (Opts.OutputPath.empty())
+ Opts.OutputPath = "-";
+ std::unique_ptr<raw_fd_ostream> FDOS =
+ getOutputStream(Opts.OutputPath, Diags, IsBinary);
+ if (!FDOS)
+ return true;
+ std::unique_ptr<raw_fd_ostream> DwoOS;
+ if (!Opts.SplitDwarfOutput.empty())
+ DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
+
+ // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
+ // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
+ std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
+
+ MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
+
+ bool PIC = false;
+ if (Opts.RelocationModel == "static") {
+ PIC = false;
+ } else if (Opts.RelocationModel == "pic") {
+ PIC = true;
+ } else {
+ assert(Opts.RelocationModel == "dynamic-no-pic" &&
+ "Invalid PIC model!");
+ PIC = false;
+ }
+
+ MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
+ if (Opts.SaveTemporaryLabels)
+ Ctx.setAllowTemporaryLabels(false);
+ if (Opts.GenDwarfForAssembly)
+ Ctx.setGenDwarfForAssembly(true);
+ if (!Opts.DwarfDebugFlags.empty())
+ Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
+ if (!Opts.DwarfDebugProducer.empty())
+ Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
+ if (!Opts.DebugCompilationDir.empty())
+ Ctx.setCompilationDir(Opts.DebugCompilationDir);
+ else {
+ // If no compilation dir is set, try to use the current directory.
+ SmallString<128> CWD;
+ if (!sys::fs::current_path(CWD))
+ Ctx.setCompilationDir(CWD);
+ }
+ if (!Opts.DebugPrefixMap.empty())
+ for (const auto &KV : Opts.DebugPrefixMap)
+ Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
+ if (!Opts.MainFileName.empty())
+ Ctx.setMainFileName(StringRef(Opts.MainFileName));
+ Ctx.setDwarfVersion(Opts.DwarfVersion);
+ if (Opts.GenDwarfForAssembly)
+ Ctx.setGenDwarfRootFile(Opts.InputFile,
+ SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
+
+ // Build up the feature string from the target feature list.
+ std::string FS;
+ if (!Opts.Features.empty()) {
+ FS = Opts.Features[0];
+ for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
+ FS += "," + Opts.Features[i];
+ }
+
+ std::unique_ptr<MCStreamer> Str;
+
+ std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
+ std::unique_ptr<MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
+
+ raw_pwrite_stream *Out = FDOS.get();
+ std::unique_ptr<buffer_ostream> BOS;
+
+ MCOptions.MCNoWarn = Opts.NoWarn;
+ MCOptions.MCFatalWarnings = Opts.FatalWarnings;
+ MCOptions.ABIName = Opts.TargetABI;
+
+ // FIXME: There is a bit of code duplication with addPassesToEmitFile.
+ if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
+ MCInstPrinter *IP = TheTarget->createMCInstPrinter(
+ llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
+
+ std::unique_ptr<MCCodeEmitter> CE;
+ if (Opts.ShowEncoding)
+ CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+ std::unique_ptr<MCAsmBackend> MAB(
+ TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+
+ auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
+ Str.reset(TheTarget->createAsmStreamer(
+ Ctx, std::move(FOut), /*asmverbose*/ true,
+ /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
+ Opts.ShowInst));
+ } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
+ Str.reset(createNullStreamer(Ctx));
+ } else {
+ assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
+ "Invalid file type!");
+ if (!FDOS->supportsSeeking()) {
+ BOS = std::make_unique<buffer_ostream>(*FDOS);
+ Out = BOS.get();
+ }
+
+ std::unique_ptr<MCCodeEmitter> CE(
+ TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+ std::unique_ptr<MCAsmBackend> MAB(
+ TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+ std::unique_ptr<MCObjectWriter> OW =
+ DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
+ : MAB->createObjectWriter(*Out);
+
+ Triple T(Opts.Triple);
+ Str.reset(TheTarget->createMCObjectStreamer(
+ T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
+ Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ true));
+ Str.get()->InitSections(Opts.NoExecStack);
+ }
+
+ // When -fembed-bitcode is passed to clang_as, a 1-byte marker
+ // is emitted in __LLVM,__asm section if the object file is MachO format.
+ if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
+ MCObjectFileInfo::IsMachO) {
+ MCSection *AsmLabel = Ctx.getMachOSection(
+ "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
+ Str.get()->SwitchSection(AsmLabel);
+ Str.get()->EmitZeros(1);
+ }
+
+ // Assembly to object compilation should leverage assembly info.
+ Str->setUseAssemblerInfoForParsing(true);
+
+ bool Failed = false;
+
+ std::unique_ptr<MCAsmParser> Parser(
+ createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
+
+ // FIXME: init MCTargetOptions from sanitizer flags here.
+ std::unique_ptr<MCTargetAsmParser> TAP(
+ TheTarget->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
+ if (!TAP)
+ Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+
+ // Set values for symbols, if any.
+ for (auto &S : Opts.SymbolDefs) {
+ auto Pair = StringRef(S).split('=');
+ auto Sym = Pair.first;
+ auto Val = Pair.second;
+ int64_t Value;
+ // We have already error checked this in the driver.
+ Val.getAsInteger(0, Value);
+ Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
+ }
+
+ if (!Failed) {
+ Parser->setTargetParser(*TAP.get());
+ Failed = Parser->Run(Opts.NoInitialTextSection);
+ }
+
+ // Close Streamer first.
+ // It might have a reference to the output stream.
+ Str.reset();
+ // Close the output stream early.
+ BOS.reset();
+ FDOS.reset();
+
+ // Delete output file if there were errors.
+ if (Failed) {
+ if (Opts.OutputPath != "-")
+ sys::fs::remove(Opts.OutputPath);
+ if (!Opts.SplitDwarfOutput.empty() && Opts.SplitDwarfOutput != "-")
+ sys::fs::remove(Opts.SplitDwarfOutput);
+ }
+
+ return Failed;
+}
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message,
+ bool GenCrashDiag) {
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ sys::Process::Exit(1);
+}
+
+int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
+ // Initialize targets and assembly printers/parsers.
+ InitializeAllTargetInfos();
+ InitializeAllTargetMCs();
+ InitializeAllAsmParsers();
+
+ // Construct our diagnostic client.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter *DiagClient
+ = new TextDiagnosticPrinter(errs(), &*DiagOpts);
+ DiagClient->setPrefix("clang -cc1as");
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ ScopedFatalErrorHandler FatalErrorHandler
+ (LLVMErrorHandler, static_cast<void*>(&Diags));
+
+ // Parse the arguments.
+ AssemblerInvocation Asm;
+ if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
+ return 1;
+
+ if (Asm.ShowHelp) {
+ getDriverOptTable().PrintHelp(
+ llvm::outs(), "clang -cc1as [options] file...",
+ "Clang Integrated Assembler",
+ /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
+ /*ShowAllAliases=*/false);
+ return 0;
+ }
+
+ // Honor -version.
+ //
+ // FIXME: Use a better -version message?
+ if (Asm.ShowVersion) {
+ llvm::cl::PrintVersionMessage();
+ return 0;
+ }
+
+ // Honor -mllvm.
+ //
+ // FIXME: Remove this, one day.
+ if (!Asm.LLVMArgs.empty()) {
+ unsigned NumArgs = Asm.LLVMArgs.size();
+ auto Args = std::make_unique<const char*[]>(NumArgs + 2);
+ Args[0] = "clang (LLVM option parsing)";
+ for (unsigned i = 0; i != NumArgs; ++i)
+ Args[i + 1] = Asm.LLVMArgs[i].c_str();
+ Args[NumArgs + 1] = nullptr;
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
+ }
+
+ // Execute the invocation, unless there were parsing errors.
+ bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now.
+ TimerGroup::printAll(errs());
+ TimerGroup::clearAll();
+
+ return !!Failed;
+}
diff --git a/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp b/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp
new file mode 100644
index 00000000000..4aadab7301b
--- /dev/null
+++ b/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp
@@ -0,0 +1,195 @@
+//===-- cc1gen_reproducer_main.cpp - Clang reproducer generator ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1gen-reproducer functionality, which
+// generates reproducers for invocations for clang-based tools.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+
+struct UnsavedFileHash {
+ std::string Name;
+ std::string MD5;
+};
+
+struct ClangInvocationInfo {
+ std::string Toolchain;
+ std::string LibclangOperation;
+ std::string LibclangOptions;
+ std::vector<std::string> Arguments;
+ std::vector<std::string> InvocationArguments;
+ std::vector<UnsavedFileHash> UnsavedFileHashes;
+ bool Dump = false;
+};
+
+} // end anonymous namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(UnsavedFileHash)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<UnsavedFileHash> {
+ static void mapping(IO &IO, UnsavedFileHash &Info) {
+ IO.mapRequired("name", Info.Name);
+ IO.mapRequired("md5", Info.MD5);
+ }
+};
+
+template <> struct MappingTraits<ClangInvocationInfo> {
+ static void mapping(IO &IO, ClangInvocationInfo &Info) {
+ IO.mapRequired("toolchain", Info.Toolchain);
+ IO.mapOptional("libclang.operation", Info.LibclangOperation);
+ IO.mapOptional("libclang.opts", Info.LibclangOptions);
+ IO.mapRequired("args", Info.Arguments);
+ IO.mapOptional("invocation-args", Info.InvocationArguments);
+ IO.mapOptional("unsaved_file_hashes", Info.UnsavedFileHashes);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+static std::string generateReproducerMetaInfo(const ClangInvocationInfo &Info) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << '{';
+ bool NeedComma = false;
+ auto EmitKey = [&](StringRef Key) {
+ if (NeedComma)
+ OS << ", ";
+ NeedComma = true;
+ OS << '"' << Key << "\": ";
+ };
+ auto EmitStringKey = [&](StringRef Key, StringRef Value) {
+ if (Value.empty())
+ return;
+ EmitKey(Key);
+ OS << '"' << Value << '"';
+ };
+ EmitStringKey("libclang.operation", Info.LibclangOperation);
+ EmitStringKey("libclang.opts", Info.LibclangOptions);
+ if (!Info.InvocationArguments.empty()) {
+ EmitKey("invocation-args");
+ OS << '[';
+ for (const auto &Arg : llvm::enumerate(Info.InvocationArguments)) {
+ if (Arg.index())
+ OS << ',';
+ OS << '"' << Arg.value() << '"';
+ }
+ OS << ']';
+ }
+ OS << '}';
+ // FIXME: Compare unsaved file hashes and report mismatch in the reproducer.
+ if (Info.Dump)
+ llvm::outs() << "REPRODUCER METAINFO: " << OS.str() << "\n";
+ return std::move(OS.str());
+}
+
+/// Generates a reproducer for a set of arguments from a specific invocation.
+static llvm::Optional<driver::Driver::CompilationDiagnosticReport>
+generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
+ const ClangInvocationInfo &Info) {
+ using namespace driver;
+ auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]);
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
+ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
+ Driver TheDriver(Argv[0], llvm::sys::getDefaultTargetTriple(), Diags);
+ TheDriver.setTargetAndMode(TargetAndMode);
+
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Argv));
+ if (C && !C->containsError()) {
+ for (const auto &J : C->getJobs()) {
+ if (const Command *Cmd = dyn_cast<Command>(&J)) {
+ Driver::CompilationDiagnosticReport Report;
+ TheDriver.generateCompilationDiagnostics(
+ *C, *Cmd, generateReproducerMetaInfo(Info), &Report);
+ return Report;
+ }
+ }
+ }
+
+ return None;
+}
+
+std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes);
+
+static void printReproducerInformation(
+ llvm::raw_ostream &OS, const ClangInvocationInfo &Info,
+ const driver::Driver::CompilationDiagnosticReport &Report) {
+ OS << "REPRODUCER:\n";
+ OS << "{\n";
+ OS << R"("files":[)";
+ for (const auto &File : llvm::enumerate(Report.TemporaryFiles)) {
+ if (File.index())
+ OS << ',';
+ OS << '"' << File.value() << '"';
+ }
+ OS << "]\n}\n";
+}
+
+int cc1gen_reproducer_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr) {
+ if (Argv.size() < 1) {
+ llvm::errs() << "error: missing invocation file\n";
+ return 1;
+ }
+ // Parse the invocation descriptor.
+ StringRef Input = Argv[0];
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
+ llvm::MemoryBuffer::getFile(Input);
+ if (!Buffer) {
+ llvm::errs() << "error: failed to read " << Input << ": "
+ << Buffer.getError().message() << "\n";
+ return 1;
+ }
+ llvm::yaml::Input YAML(Buffer.get()->getBuffer());
+ ClangInvocationInfo InvocationInfo;
+ YAML >> InvocationInfo;
+ if (Argv.size() > 1 && Argv[1] == StringRef("-v"))
+ InvocationInfo.Dump = true;
+
+ // Create an invocation that will produce the reproducer.
+ std::vector<const char *> DriverArgs;
+ for (const auto &Arg : InvocationInfo.Arguments)
+ DriverArgs.push_back(Arg.c_str());
+ std::string Path = GetExecutablePath(Argv0, /*CanonicalPrefixes=*/true);
+ DriverArgs[0] = Path.c_str();
+ llvm::Optional<driver::Driver::CompilationDiagnosticReport> Report =
+ generateReproducerForInvocationArguments(DriverArgs, InvocationInfo);
+
+ // Emit the information about the reproduce files to stdout.
+ int Result = 1;
+ if (Report) {
+ printReproducerInformation(llvm::outs(), InvocationInfo, *Report);
+ Result = 0;
+ }
+
+ // Remove the input file.
+ llvm::sys::fs::remove(Input);
+ return Result;
+}
diff --git a/gnu/llvm/clang/tools/driver/driver.cpp b/gnu/llvm/clang/tools/driver/driver.cpp
new file mode 100644
index 00000000000..7b3968341cc
--- /dev/null
+++ b/gnu/llvm/clang/tools/driver/driver.cpp
@@ -0,0 +1,557 @@
+//===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang driver; it is a thin wrapper
+// for functionality in the Driver clang library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Driver.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/Stack.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/ToolChain.h"
+#include "clang/Frontend/ChainedDiagnosticConsumer.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/BuryPointer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <set>
+#include <system_error>
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm::opt;
+
+std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
+ if (!CanonicalPrefixes) {
+ SmallString<128> ExecutablePath(Argv0);
+ // Do a PATH lookup if Argv0 isn't a valid path.
+ if (!llvm::sys::fs::exists(ExecutablePath))
+ if (llvm::ErrorOr<std::string> P =
+ llvm::sys::findProgramByName(ExecutablePath))
+ ExecutablePath = *P;
+ return ExecutablePath.str();
+ }
+
+ // This just needs to be some symbol in the binary; C++ doesn't
+ // allow taking the address of ::main however.
+ void *P = (void*) (intptr_t) GetExecutablePath;
+ return llvm::sys::fs::getMainExecutable(Argv0, P);
+}
+
+static const char *GetStableCStr(std::set<std::string> &SavedStrings,
+ StringRef S) {
+ return SavedStrings.insert(S).first->c_str();
+}
+
+/// ApplyQAOverride - Apply a list of edits to the input argument lists.
+///
+/// The input string is a space separate list of edits to perform,
+/// they are applied in order to the input argument lists. Edits
+/// should be one of the following forms:
+///
+/// '#': Silence information about the changes to the command line arguments.
+///
+/// '^': Add FOO as a new argument at the beginning of the command line.
+///
+/// '+': Add FOO as a new argument at the end of the command line.
+///
+/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
+/// line.
+///
+/// 'xOPTION': Removes all instances of the literal argument OPTION.
+///
+/// 'XOPTION': Removes all instances of the literal argument OPTION,
+/// and the following argument.
+///
+/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
+/// at the end of the command line.
+///
+/// \param OS - The stream to write edit information to.
+/// \param Args - The vector of command line arguments.
+/// \param Edit - The override command to perform.
+/// \param SavedStrings - Set to use for storing string representations.
+static void ApplyOneQAOverride(raw_ostream &OS,
+ SmallVectorImpl<const char*> &Args,
+ StringRef Edit,
+ std::set<std::string> &SavedStrings) {
+ // This does not need to be efficient.
+
+ if (Edit[0] == '^') {
+ const char *Str =
+ GetStableCStr(SavedStrings, Edit.substr(1));
+ OS << "### Adding argument " << Str << " at beginning\n";
+ Args.insert(Args.begin() + 1, Str);
+ } else if (Edit[0] == '+') {
+ const char *Str =
+ GetStableCStr(SavedStrings, Edit.substr(1));
+ OS << "### Adding argument " << Str << " at end\n";
+ Args.push_back(Str);
+ } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
+ Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
+ StringRef MatchPattern = Edit.substr(2).split('/').first;
+ StringRef ReplPattern = Edit.substr(2).split('/').second;
+ ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
+
+ for (unsigned i = 1, e = Args.size(); i != e; ++i) {
+ // Ignore end-of-line response file markers
+ if (Args[i] == nullptr)
+ continue;
+ std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
+
+ if (Repl != Args[i]) {
+ OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
+ Args[i] = GetStableCStr(SavedStrings, Repl);
+ }
+ }
+ } else if (Edit[0] == 'x' || Edit[0] == 'X') {
+ auto Option = Edit.substr(1);
+ for (unsigned i = 1; i < Args.size();) {
+ if (Option == Args[i]) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ if (Edit[0] == 'X') {
+ if (i < Args.size()) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ OS << "### Invalid X edit, end of command line!\n";
+ }
+ } else
+ ++i;
+ }
+ } else if (Edit[0] == 'O') {
+ for (unsigned i = 1; i < Args.size();) {
+ const char *A = Args[i];
+ // Ignore end-of-line response file markers
+ if (A == nullptr)
+ continue;
+ if (A[0] == '-' && A[1] == 'O' &&
+ (A[2] == '\0' ||
+ (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
+ ('0' <= A[2] && A[2] <= '9'))))) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ ++i;
+ }
+ OS << "### Adding argument " << Edit << " at end\n";
+ Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
+ } else {
+ OS << "### Unrecognized edit: " << Edit << "\n";
+ }
+}
+
+/// ApplyQAOverride - Apply a comma separate list of edits to the
+/// input argument lists. See ApplyOneQAOverride.
+static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
+ const char *OverrideStr,
+ std::set<std::string> &SavedStrings) {
+ raw_ostream *OS = &llvm::errs();
+
+ if (OverrideStr[0] == '#') {
+ ++OverrideStr;
+ OS = &llvm::nulls();
+ }
+
+ *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
+
+ // This does not need to be efficient.
+
+ const char *S = OverrideStr;
+ while (*S) {
+ const char *End = ::strchr(S, ' ');
+ if (!End)
+ End = S + strlen(S);
+ if (End != S)
+ ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
+ S = End;
+ if (*S != '\0')
+ ++S;
+ }
+}
+
+extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
+extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr);
+extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
+ const char *Argv0, void *MainAddr);
+
+static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
+ SmallVectorImpl<const char *> &ArgVector,
+ std::set<std::string> &SavedStrings) {
+ // Put target and mode arguments at the start of argument list so that
+ // arguments specified in command line could override them. Avoid putting
+ // them at index 0, as an option like '-cc1' must remain the first.
+ int InsertionPoint = 0;
+ if (ArgVector.size() > 0)
+ ++InsertionPoint;
+
+ if (NameParts.DriverMode) {
+ // Add the mode flag to the arguments.
+ ArgVector.insert(ArgVector.begin() + InsertionPoint,
+ GetStableCStr(SavedStrings, NameParts.DriverMode));
+ }
+
+ if (NameParts.TargetIsValid) {
+ const char *arr[] = {"-target", GetStableCStr(SavedStrings,
+ NameParts.TargetPrefix)};
+ ArgVector.insert(ArgVector.begin() + InsertionPoint,
+ std::begin(arr), std::end(arr));
+ }
+}
+
+static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
+ SmallVectorImpl<const char *> &Opts) {
+ llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
+ // The first instance of '#' should be replaced with '=' in each option.
+ for (const char *Opt : Opts)
+ if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#')))
+ *NumberSignPtr = '=';
+}
+
+static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
+ // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
+ TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
+ if (TheDriver.CCPrintOptions)
+ TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+
+ // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
+ TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
+ if (TheDriver.CCPrintHeaders)
+ TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+
+ // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
+ TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
+ if (TheDriver.CCLogDiagnostics)
+ TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+}
+
+static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
+ const std::string &Path) {
+ // If the clang binary happens to be named cl.exe for compatibility reasons,
+ // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
+ StringRef ExeBasename(llvm::sys::path::stem(Path));
+ if (ExeBasename.equals_lower("cl"))
+ ExeBasename = "clang-cl";
+ DiagClient->setPrefix(ExeBasename);
+}
+
+// This lets us create the DiagnosticsEngine with a properly-filled-out
+// DiagnosticOptions instance.
+static DiagnosticOptions *
+CreateAndPopulateDiagOpts(ArrayRef<const char *> argv, bool &UseNewCC1Process) {
+ auto *DiagOpts = new DiagnosticOptions;
+ unsigned MissingArgIndex, MissingArgCount;
+ InputArgList Args = getDriverOptTable().ParseArgs(
+ argv.slice(1), MissingArgIndex, MissingArgCount);
+ // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
+ // Any errors that would be diagnosed here will also be diagnosed later,
+ // when the DiagnosticsEngine actually exists.
+ (void)ParseDiagnosticArgs(*DiagOpts, Args);
+
+ UseNewCC1Process =
+ Args.hasFlag(clang::driver::options::OPT_fno_integrated_cc1,
+ clang::driver::options::OPT_fintegrated_cc1,
+ /*Default=*/CLANG_SPAWN_CC1);
+
+ return DiagOpts;
+}
+
+static void SetInstallDir(SmallVectorImpl<const char *> &argv,
+ Driver &TheDriver, bool CanonicalPrefixes) {
+ // Attempt to find the original path used to invoke the driver, to determine
+ // the installed path. We do this manually, because we want to support that
+ // path being a symlink.
+ SmallString<128> InstalledPath(argv[0]);
+
+ // Do a PATH lookup, if there are no directory components.
+ if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
+ if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
+ llvm::sys::path::filename(InstalledPath.str())))
+ InstalledPath = *Tmp;
+
+ // FIXME: We don't actually canonicalize this, we just make it absolute.
+ if (CanonicalPrefixes)
+ llvm::sys::fs::make_absolute(InstalledPath);
+
+ StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
+ if (llvm::sys::fs::exists(InstalledPathParent))
+ TheDriver.setInstalledDir(InstalledPathParent);
+}
+
+static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
+ // If we call the cc1 tool from the clangDriver library (through
+ // Driver::CC1Main), we need to clean up the options usage count. The options
+ // are currently global, and they might have been used previously by the
+ // driver.
+ llvm::cl::ResetAllOptionOccurrences();
+
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+ llvm::cl::ExpandResponseFiles(Saver, &llvm::cl::TokenizeGNUCommandLine, ArgV,
+ /*MarkEOLs=*/false);
+ StringRef Tool = ArgV[1];
+ void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
+ if (Tool == "-cc1")
+ return cc1_main(makeArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
+ if (Tool == "-cc1as")
+ return cc1as_main(makeArrayRef(ArgV).slice(2), ArgV[0],
+ GetExecutablePathVP);
+ if (Tool == "-cc1gen-reproducer")
+ return cc1gen_reproducer_main(makeArrayRef(ArgV).slice(2), ArgV[0],
+ GetExecutablePathVP);
+ // Reject unknown tools.
+ llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
+ << "Valid tools include '-cc1' and '-cc1as'.\n";
+ return 1;
+}
+
+int main(int argc_, const char **argv_) {
+ noteBottomOfStack();
+ llvm::InitLLVM X(argc_, argv_);
+ SmallVector<const char *, 256> argv(argv_, argv_ + argc_);
+
+ if (llvm::sys::Process::FixupStandardFileDescriptors())
+ return 1;
+
+ llvm::InitializeAllTargets();
+ auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
+
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver(A);
+
+ // Parse response files using the GNU syntax, unless we're in CL mode. There
+ // are two ways to put clang in CL compatibility mode: argv[0] is either
+ // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
+ // command line parsing can't happen until after response file parsing, so we
+ // have to manually search for a --driver-mode=cl argument the hard way.
+ // Finally, our -cc1 tools don't care which tokenization mode we use because
+ // response files written by clang will tokenize the same way in either mode.
+ bool ClangCLMode = false;
+ if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
+ llvm::find_if(argv, [](const char *F) {
+ return F && strcmp(F, "--driver-mode=cl") == 0;
+ }) != argv.end()) {
+ ClangCLMode = true;
+ }
+ enum { Default, POSIX, Windows } RSPQuoting = Default;
+ for (const char *F : argv) {
+ if (strcmp(F, "--rsp-quoting=posix") == 0)
+ RSPQuoting = POSIX;
+ else if (strcmp(F, "--rsp-quoting=windows") == 0)
+ RSPQuoting = Windows;
+ }
+
+ // Determines whether we want nullptr markers in argv to indicate response
+ // files end-of-lines. We only use this for the /LINK driver argument with
+ // clang-cl.exe on Windows.
+ bool MarkEOLs = ClangCLMode;
+
+ llvm::cl::TokenizerCallback Tokenizer;
+ if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
+ Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
+ else
+ Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
+
+ if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
+ MarkEOLs = false;
+ llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs);
+
+ // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
+ // file.
+ auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
+ [](const char *A) { return A != nullptr; });
+ if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
+ // If -cc1 came from a response file, remove the EOL sentinels.
+ if (MarkEOLs) {
+ auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
+ argv.resize(newEnd - argv.begin());
+ }
+ return ExecuteCC1Tool(argv);
+ }
+
+ // Handle options that need handling before the real command line parsing in
+ // Driver::BuildCompilation()
+ bool CanonicalPrefixes = true;
+ for (int i = 1, size = argv.size(); i < size; ++i) {
+ // Skip end-of-line response file markers
+ if (argv[i] == nullptr)
+ continue;
+ if (StringRef(argv[i]) == "-no-canonical-prefixes") {
+ CanonicalPrefixes = false;
+ break;
+ }
+ }
+
+ // Handle CL and _CL_ which permits additional command line options to be
+ // prepended or appended.
+ if (ClangCLMode) {
+ // Arguments in "CL" are prepended.
+ llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
+ if (OptCL.hasValue()) {
+ SmallVector<const char *, 8> PrependedOpts;
+ getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
+
+ // Insert right after the program name to prepend to the argument list.
+ argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
+ }
+ // Arguments in "_CL_" are appended.
+ llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
+ if (Opt_CL_.hasValue()) {
+ SmallVector<const char *, 8> AppendedOpts;
+ getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
+
+ // Insert at the end of the argument list to append.
+ argv.append(AppendedOpts.begin(), AppendedOpts.end());
+ }
+ }
+
+ std::set<std::string> SavedStrings;
+ // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
+ // scenes.
+ if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
+ // FIXME: Driver shouldn't take extra initial argument.
+ ApplyQAOverride(argv, OverrideStr, SavedStrings);
+ }
+
+ std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
+
+ // Whether the cc1 tool should be called inside the current process, or if we
+ // should spawn a new clang subprocess (old behavior).
+ // Not having an additional process saves some execution time of Windows,
+ // and makes debugging and profiling easier.
+ bool UseNewCC1Process;
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+ CreateAndPopulateDiagOpts(argv, UseNewCC1Process);
+
+ TextDiagnosticPrinter *DiagClient
+ = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ FixupDiagPrefixExeName(DiagClient, Path);
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+
+ if (!DiagOpts->DiagnosticSerializationFile.empty()) {
+ auto SerializedConsumer =
+ clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
+ &*DiagOpts, /*MergeChildRecords=*/true);
+ Diags.setClient(new ChainedDiagnosticConsumer(
+ Diags.takeClient(), std::move(SerializedConsumer)));
+ }
+
+ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
+
+ Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
+ SetInstallDir(argv, TheDriver, CanonicalPrefixes);
+ TheDriver.setTargetAndMode(TargetAndMode);
+
+ insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
+
+ SetBackdoorDriverOutputsFromEnvVars(TheDriver);
+
+ if (!UseNewCC1Process) {
+ TheDriver.CC1Main = &ExecuteCC1Tool;
+ // Ensure the CC1Command actually catches cc1 crashes
+ llvm::CrashRecoveryContext::Enable();
+ }
+
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
+ int Res = 1;
+ bool IsCrash = false;
+ if (C && !C->containsError()) {
+ SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
+ Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
+
+ // Force a crash to test the diagnostics.
+ if (TheDriver.GenReproducer) {
+ Diags.Report(diag::err_drv_force_crash)
+ << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
+
+ // Pretend that every command failed.
+ FailingCommands.clear();
+ for (const auto &J : C->getJobs())
+ if (const Command *C = dyn_cast<Command>(&J))
+ FailingCommands.push_back(std::make_pair(-1, C));
+ }
+
+ for (const auto &P : FailingCommands) {
+ int CommandRes = P.first;
+ const Command *FailingCommand = P.second;
+ if (!Res)
+ Res = CommandRes;
+
+ // If result status is < 0, then the driver command signalled an error.
+ // If result status is 70, then the driver command reported a fatal error.
+ // On Windows, abort will return an exit code of 3. In these cases,
+ // generate additional diagnostic information if possible.
+ IsCrash = CommandRes < 0 || CommandRes == 70;
+#ifdef _WIN32
+ IsCrash |= CommandRes == 3;
+#endif
+ if (IsCrash) {
+ TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
+ break;
+ }
+ }
+ }
+
+ Diags.getClient()->finish();
+
+ if (!UseNewCC1Process && IsCrash) {
+ // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because
+ // the internal linked list might point to already released stack frames.
+ llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup());
+ } else {
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now. This happens in -disable-free mode.
+ llvm::TimerGroup::printAll(llvm::errs());
+ llvm::TimerGroup::clearAll();
+ }
+
+#ifdef _WIN32
+ // Exit status should not be negative on Win32, unless abnormal termination.
+ // Once abnormal termination was caught, negative status should not be
+ // propagated.
+ if (Res < 0)
+ Res = 1;
+#endif
+
+ // If we have multiple failing commands, we return the result of the first
+ // failing command.
+ return Res;
+}