[llvm] 3e57aa3 - [llvm-driver] Reinvoke clang as described by llvm driver extra args

Alex Brachet via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 10 11:42:46 PST 2023


Author: Alex Brachet
Date: 2023-02-10T19:42:32Z
New Revision: 3e57aa304f15a0821e5bcc90bd346529fed6658d

URL: https://github.com/llvm/llvm-project/commit/3e57aa304f15a0821e5bcc90bd346529fed6658d
DIFF: https://github.com/llvm/llvm-project/commit/3e57aa304f15a0821e5bcc90bd346529fed6658d.diff

LOG: [llvm-driver] Reinvoke clang as described by llvm driver extra args

Differential Revision: https://reviews.llvm.org/D137800

Added: 
    

Modified: 
    clang/include/clang/Driver/Driver.h
    clang/include/clang/Driver/Job.h
    clang/lib/Driver/Driver.cpp
    clang/lib/Driver/Job.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/test/Analysis/scan-build/lit.local.cfg
    clang/test/CodeGen/debug-info-codeview-buildinfo.c
    clang/test/Driver/check-time-trace.cpp
    clang/tools/driver/cc1gen_reproducer_main.cpp
    clang/tools/driver/driver.cpp
    clang/tools/scan-build/libexec/ccc-analyzer
    llvm/cmake/modules/llvm-driver-template.cpp.in
    llvm/include/llvm/Support/LLVMDriver.h
    llvm/lib/Support/Path.cpp
    llvm/lib/Support/Unix/Path.inc
    llvm/lib/Support/Windows/Path.inc
    llvm/tools/llvm-driver/llvm-driver.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index 4bbb113b6cf59..c9136ec4ae690 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -21,6 +21,7 @@
 #include "clang/Driver/Types.h"
 #include "clang/Driver/Util.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Option/Arg.h"
@@ -261,7 +262,8 @@ class Driver {
   /// When the clangDriver lib is used through clang.exe, this provides a
   /// shortcut for executing the -cc1 command-line directly, in the same
   /// process.
-  typedef int (*CC1ToolFunc)(SmallVectorImpl<const char *> &ArgV);
+  using CC1ToolFunc =
+      llvm::function_ref<int(SmallVectorImpl<const char *> &ArgV)>;
   CC1ToolFunc CC1Main = nullptr;
 
 private:
@@ -286,6 +288,12 @@ class Driver {
   /// Arguments originated from command line.
   std::unique_ptr<llvm::opt::InputArgList> CLOptions;
 
+  /// If this is non-null, the driver will prepend this argument before
+  /// reinvoking clang. This is useful for the llvm-driver where clang's
+  /// realpath will be to the llvm binary and not clang, so it must pass
+  /// "clang" as it's first argument.
+  const char *PrependArg;
+
   /// Whether to check that input files exist when constructing compilation
   /// jobs.
   unsigned CheckInputsExist : 1;
@@ -383,6 +391,9 @@ class Driver {
   bool getProbePrecompiled() const { return ProbePrecompiled; }
   void setProbePrecompiled(bool Value) { ProbePrecompiled = Value; }
 
+  const char *getPrependArg() const { return PrependArg; }
+  void setPrependArg(const char *Value) { PrependArg = Value; }
+
   void setTargetAndMode(const ParsedClangName &TM) { ClangNameParts = TM; }
 
   const std::string &getTitle() { return DriverTitle; }

diff  --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h
index e3fa92d6ad5fd..e866679dc1a91 100644
--- a/clang/include/clang/Driver/Job.h
+++ b/clang/include/clang/Driver/Job.h
@@ -116,6 +116,9 @@ class Command {
   /// The executable to run.
   const char *Executable;
 
+  /// Optional argument to prepend.
+  const char *PrependArg;
+
   /// The list of program arguments (not including the implicit first
   /// argument, which will be the executable).
   llvm::opt::ArgStringList Arguments;
@@ -169,7 +172,8 @@ class Command {
   Command(const Action &Source, const Tool &Creator,
           ResponseFileSupport ResponseSupport, const char *Executable,
           const llvm::opt::ArgStringList &Arguments, ArrayRef<InputInfo> Inputs,
-          ArrayRef<InputInfo> Outputs = std::nullopt);
+          ArrayRef<InputInfo> Outputs = std::nullopt,
+          const char *PrependArg = nullptr);
   // FIXME: This really shouldn't be copyable, but is currently copied in some
   // error handling in Driver::generateCompilationDiagnostics.
   Command(const Command &) = default;
@@ -242,7 +246,8 @@ class CC1Command : public Command {
              ResponseFileSupport ResponseSupport, const char *Executable,
              const llvm::opt::ArgStringList &Arguments,
              ArrayRef<InputInfo> Inputs,
-             ArrayRef<InputInfo> Outputs = std::nullopt);
+             ArrayRef<InputInfo> Outputs = std::nullopt,
+             const char *PrependArg = nullptr);
 
   void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
              CrashReportInfo *CrashInfo = nullptr) const override;

diff  --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 8d8bd55cabae6..0567441225d0c 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -200,7 +200,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
       DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
       CCLogDiagnostics(false), CCGenDiagnostics(false),
       CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
-      CheckInputsExist(true), ProbePrecompiled(true),
+      PrependArg(nullptr), CheckInputsExist(true), ProbePrecompiled(true),
       SuppressMissingInputWarning(false) {
   // Provide a sane fallback if no VFS is specified.
   if (!this->VFS)

diff  --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index ec355ceb84a9c..f85f55cd1ff54 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -38,9 +38,10 @@ using namespace driver;
 Command::Command(const Action &Source, const Tool &Creator,
                  ResponseFileSupport ResponseSupport, const char *Executable,
                  const llvm::opt::ArgStringList &Arguments,
-                 ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs)
+                 ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs,
+                 const char *PrependArg)
     : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport),
-      Executable(Executable), Arguments(Arguments) {
+      Executable(Executable), PrependArg(PrependArg), Arguments(Arguments) {
   for (const auto &II : Inputs)
     if (II.isFilename())
       InputInfoList.push_back(II);
@@ -144,6 +145,10 @@ void Command::buildArgvForResponseFile(
   for (const auto *InputName : InputFileList)
     Inputs.insert(InputName);
   Out.push_back(Executable);
+
+  if (PrependArg)
+    Out.push_back(PrependArg);
+
   // In a file list, build args vector ignoring parameters that will go in the
   // response file (elements of the InputFileList vector)
   bool FirstInput = true;
@@ -209,6 +214,9 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
   if (ResponseFile != nullptr) {
     buildArgvForResponseFile(ArgsRespFile);
     Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
+  } else if (PrependArg) {
+    OS << ' ';
+    llvm::sys::printArg(OS, PrependArg, /*Quote=*/true);
   }
 
   bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
@@ -321,6 +329,8 @@ int Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
   SmallVector<const char *, 128> Argv;
   if (ResponseFile == nullptr) {
     Argv.push_back(Executable);
+    if (PrependArg)
+      Argv.push_back(PrependArg);
     Argv.append(Arguments.begin(), Arguments.end());
     Argv.push_back(nullptr);
   } else {
@@ -382,9 +392,10 @@ CC1Command::CC1Command(const Action &Source, const Tool &Creator,
                        ResponseFileSupport ResponseSupport,
                        const char *Executable,
                        const llvm::opt::ArgStringList &Arguments,
-                       ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs)
+                       ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs,
+                       const char *PrependArg)
     : Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs,
-              Outputs) {
+              Outputs, PrependArg) {
   InProcess = true;
 }
 

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6000b11a28474..c97856a47686a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4979,7 +4979,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
     C.addCommand(std::make_unique<Command>(
         JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(),
-        CmdArgs, Inputs, Output));
+        CmdArgs, Inputs, Output, D.getPrependArg()));
     return;
   }
 
@@ -7408,13 +7408,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (D.CC1Main && !D.CCGenDiagnostics) {
     // Invoke the CC1 directly in this process
-    C.addCommand(std::make_unique<CC1Command>(JA, *this,
-                                              ResponseFileSupport::AtFileUTF8(),
-                                              Exec, CmdArgs, Inputs, Output));
+    C.addCommand(std::make_unique<CC1Command>(
+        JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+        Output, D.getPrependArg()));
   } else {
-    C.addCommand(std::make_unique<Command>(JA, *this,
-                                           ResponseFileSupport::AtFileUTF8(),
-                                           Exec, CmdArgs, Inputs, Output));
+    C.addCommand(std::make_unique<Command>(
+        JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+        Output, D.getPrependArg()));
   }
 
   // Make the compile command echo its inputs for /showFilenames.
@@ -8173,13 +8173,13 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
   const char *Exec = getToolChain().getDriver().getClangProgramPath();
   if (D.CC1Main && !D.CCGenDiagnostics) {
     // Invoke cc1as directly in this process.
-    C.addCommand(std::make_unique<CC1Command>(JA, *this,
-                                              ResponseFileSupport::AtFileUTF8(),
-                                              Exec, CmdArgs, Inputs, Output));
+    C.addCommand(std::make_unique<CC1Command>(
+        JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+        Output, D.getPrependArg()));
   } else {
-    C.addCommand(std::make_unique<Command>(JA, *this,
-                                           ResponseFileSupport::AtFileUTF8(),
-                                           Exec, CmdArgs, Inputs, Output));
+    C.addCommand(std::make_unique<Command>(
+        JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs,
+        Output, D.getPrependArg()));
   }
 }
 

diff  --git a/clang/test/Analysis/scan-build/lit.local.cfg b/clang/test/Analysis/scan-build/lit.local.cfg
index 09ed921714786..0c28dc63b5e81 100644
--- a/clang/test/Analysis/scan-build/lit.local.cfg
+++ b/clang/test/Analysis/scan-build/lit.local.cfg
@@ -7,6 +7,8 @@ import os
 use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
 config.test_format = lit.formats.ShTest(use_lit_shell == "0")
 
+clang_path = config.clang if config.have_llvm_driver else os.path.realpath(config.clang)
+
 config.substitutions.append(('%scan-build',
                              '\'%s\' --use-analyzer=%s ' % (
                                  lit.util.which('scan-build',
@@ -15,4 +17,4 @@ config.substitutions.append(('%scan-build',
                                                     'tools',
                                                     'scan-build',
                                                     'bin')),
-                                 os.path.realpath(config.clang))))
+                                 clang_path)))

diff  --git a/clang/test/CodeGen/debug-info-codeview-buildinfo.c b/clang/test/CodeGen/debug-info-codeview-buildinfo.c
index e1c6f3655f379..4096fac5f7437 100644
--- a/clang/test/CodeGen/debug-info-codeview-buildinfo.c
+++ b/clang/test/CodeGen/debug-info-codeview-buildinfo.c
@@ -19,7 +19,7 @@ int main(void) { return 42; }
 // CHECK: 0x[[PWD:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[PWDVAL:.+]]
 // CHECK: 0x[[FILEPATH:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[FILEPATHVAL:.+[\\/]debug-info-codeview-buildinfo.c]]
 // CHECK: 0x[[ZIPDB:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String:
-// CHECK: 0x[[TOOL:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[TOOLVAL:.+[\\/]clang.*]]
+// CHECK: 0x[[TOOL:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[TOOLVAL:.+[\\/][clang|llvm].*]]
 // CHECK: 0x[[CMDLINE:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: "-cc1
 // CHECK: 0x{{.+}} | LF_BUILDINFO [size = {{.+}}]
 // CHECK-NEXT:          0x[[PWD]]: `[[PWDVAL]]`

diff  --git a/clang/test/Driver/check-time-trace.cpp b/clang/test/Driver/check-time-trace.cpp
index 52b3e71394fba..32940500db1bc 100644
--- a/clang/test/Driver/check-time-trace.cpp
+++ b/clang/test/Driver/check-time-trace.cpp
@@ -27,7 +27,7 @@
 // CHECK-NEXT: "pid":
 // CHECK-NEXT: "tid":
 // CHECK-NEXT: "ts":
-// CHECK:      "name": "clang{{.*}}"
+// CHECK:      "name": "{{clang|llvm}}{{.*}}"
 // CHECK:      "name": "process_name"
 // CHECK:      "name": "thread_name"
 

diff  --git a/clang/tools/driver/cc1gen_reproducer_main.cpp b/clang/tools/driver/cc1gen_reproducer_main.cpp
index f9d9cab3fab19..e97fa3d277566 100644
--- a/clang/tools/driver/cc1gen_reproducer_main.cpp
+++ b/clang/tools/driver/cc1gen_reproducer_main.cpp
@@ -18,6 +18,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LLVMDriver.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -111,7 +112,8 @@ static std::string generateReproducerMetaInfo(const ClangInvocationInfo &Info) {
 /// Generates a reproducer for a set of arguments from a specific invocation.
 static std::optional<driver::Driver::CompilationDiagnosticReport>
 generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
-                                         const ClangInvocationInfo &Info) {
+                                         const ClangInvocationInfo &Info,
+                                         const llvm::ToolContext &ToolContext) {
   using namespace driver;
   auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]);
 
@@ -120,8 +122,11 @@ generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
   ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
-  Driver TheDriver(Argv[0], llvm::sys::getDefaultTargetTriple(), Diags);
+  Driver TheDriver(ToolContext.Path, llvm::sys::getDefaultTargetTriple(),
+                   Diags);
   TheDriver.setTargetAndMode(TargetAndMode);
+  if (ToolContext.NeedsPrependArg)
+    TheDriver.setPrependArg(ToolContext.PrependArg);
 
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Argv));
   if (C && !C->containsError()) {
@@ -155,7 +160,8 @@ static void printReproducerInformation(
 }
 
 int cc1gen_reproducer_main(ArrayRef<const char *> Argv, const char *Argv0,
-                           void *MainAddr) {
+                           void *MainAddr,
+                           const llvm::ToolContext &ToolContext) {
   if (Argv.size() < 1) {
     llvm::errs() << "error: missing invocation file\n";
     return 1;
@@ -182,7 +188,8 @@ int cc1gen_reproducer_main(ArrayRef<const char *> Argv, const char *Argv0,
   std::string Path = GetExecutablePath(Argv0, /*CanonicalPrefixes=*/true);
   DriverArgs[0] = Path.c_str();
   std::optional<driver::Driver::CompilationDiagnosticReport> Report =
-      generateReproducerForInvocationArguments(DriverArgs, InvocationInfo);
+      generateReproducerForInvocationArguments(DriverArgs, InvocationInfo,
+                                               ToolContext);
 
   // Emit the information about the reproduce files to stdout.
   int Result = 1;

diff  --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 7124742795501..52d391fc69712 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -211,7 +211,8 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
 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);
+                                  const char *Argv0, void *MainAddr,
+                                  const llvm::ToolContext &);
 
 static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
                                     SmallVectorImpl<const char *> &ArgVector,
@@ -342,7 +343,8 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv,
     TheDriver.setInstalledDir(InstalledPathParent);
 }
 
-static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
+static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
+                          const llvm::ToolContext &ToolContext) {
   // 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
@@ -363,14 +365,14 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
     return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
   if (Tool == "-cc1gen-reproducer")
     return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
-                                  GetExecutablePathVP);
+                                  GetExecutablePathVP, ToolContext);
   // Reject unknown tools.
   llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
                << "Valid tools include '-cc1' and '-cc1as'.\n";
   return 1;
 }
 
-int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
+int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
   noteBottomOfStack();
   llvm::InitLLVM X(Argc, Argv);
   llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL
@@ -386,15 +388,18 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
   llvm::BumpPtrAllocator A;
   llvm::StringSaver Saver(A);
 
+  const char *ProgName =
+      ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path;
+
   // Parse response files using the GNU syntax, unless we're in CL mode. There
-  // are two ways to put clang in CL compatibility mode: Args[0] is either
+  // are two ways to put clang in CL compatibility mode: ProgName 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 =
-      IsClangCL(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1)));
+      IsClangCL(getDriverMode(ProgName, llvm::ArrayRef(Args).slice(1)));
   enum { Default, POSIX, Windows } RSPQuoting = Default;
   for (const char *F : Args) {
     if (strcmp(F, "--rsp-quoting=posix") == 0)
@@ -433,7 +438,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
       auto newEnd = std::remove(Args.begin(), Args.end(), nullptr);
       Args.resize(newEnd - Args.begin());
     }
-    return ExecuteCC1Tool(Args);
+    return ExecuteCC1Tool(Args, ToolContext);
   }
 
   // Handle options that need handling before the real command line parsing in
@@ -480,7 +485,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
     ApplyQAOverride(Args, OverrideStr, SavedStrings);
   }
 
-  std::string Path = GetExecutablePath(Args[0], CanonicalPrefixes);
+  std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes);
 
   // Whether the cc1 tool should be called inside the current process, or if we
   // should spawn a new clang subprocess (old behavior).
@@ -498,7 +503,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
 
   TextDiagnosticPrinter *DiagClient
     = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
-  FixupDiagPrefixExeName(DiagClient, Path);
+  FixupDiagPrefixExeName(DiagClient, ProgName);
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
@@ -516,8 +521,15 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
 
   Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
   SetInstallDir(Args, TheDriver, CanonicalPrefixes);
-  auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]);
+  auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName);
   TheDriver.setTargetAndMode(TargetAndMode);
+  // If -canonical-prefixes is set, GetExecutablePath will have resolved Path
+  // to the llvm driver binary, not clang. In this case, we need to use
+  // PrependArg which should be clang-*. Checking just CanonicalPrefixes is
+  // safe even in the normal case because PrependArg will be null so
+  // setPrependArg will be a no-op.
+  if (ToolContext.NeedsPrependArg || CanonicalPrefixes)
+    TheDriver.setPrependArg(ToolContext.PrependArg);
 
   insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings);
 
@@ -525,7 +537,9 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &) {
     return 1;
 
   if (!UseNewCC1Process) {
-    TheDriver.CC1Main = &ExecuteCC1Tool;
+    TheDriver.CC1Main = [&ToolContext](SmallVectorImpl<const char *> &ArgV) {
+      return ExecuteCC1Tool(ArgV, ToolContext);
+    };
     // Ensure the CC1Command actually catches cc1 crashes
     llvm::CrashRecoveryContext::Enable();
   }

diff  --git a/clang/tools/scan-build/libexec/ccc-analyzer b/clang/tools/scan-build/libexec/ccc-analyzer
index 0c900293956f6..60796a543fcd0 100755
--- a/clang/tools/scan-build/libexec/ccc-analyzer
+++ b/clang/tools/scan-build/libexec/ccc-analyzer
@@ -201,7 +201,13 @@ sub GetCCArgs {
   $line =~ s/^\s+|\s+$//g;
   my @items = quotewords('\s+', 0, $line);
   my $cmd = shift @items;
-  die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/));
+  die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/ || basename($cmd) =~ /llvm/));
+  # If this is the llvm-driver the internal command will look like "llvm clang ...".
+  # Later this will be invoked like "clang clang ...", so skip over it.
+  if (basename($cmd) =~ /llvm/) {
+    die "Expected first arg to llvm driver to be 'clang'" if $items[0] ne "clang";
+    shift @items;
+  }
   return \@items;
 }
 

diff  --git a/llvm/cmake/modules/llvm-driver-template.cpp.in b/llvm/cmake/modules/llvm-driver-template.cpp.in
index a828b6dadfbde..16c4fb3471463 100644
--- a/llvm/cmake/modules/llvm-driver-template.cpp.in
+++ b/llvm/cmake/modules/llvm-driver-template.cpp.in
@@ -11,4 +11,6 @@
 
 int @TOOL_NAME at _main(int argc, char **, const llvm::ToolContext &);
 
-int main(int argc, char **argv) { return @TOOL_NAME at _main(argc, argv, {}); }
+int main(int argc, char **argv) {
+  return @TOOL_NAME at _main(argc, argv, {argv[0], nullptr, false});
+}

diff  --git a/llvm/include/llvm/Support/LLVMDriver.h b/llvm/include/llvm/Support/LLVMDriver.h
index 1e00c056ec4d1..1c68f50707770 100644
--- a/llvm/include/llvm/Support/LLVMDriver.h
+++ b/llvm/include/llvm/Support/LLVMDriver.h
@@ -9,9 +9,20 @@
 #ifndef LLVM_SUPPORT_LLVMDRIVER_H
 #define LLVM_SUPPORT_LLVMDRIVER_H
 
+#include "llvm/ADT/SmallVector.h"
+
 namespace llvm {
 
-struct ToolContext {};
+struct ToolContext {
+  const char *Path;
+  const char *PrependArg;
+  // PrependArg will be added unconditionally by the llvm-driver, but
+  // NeedsPrependArg will be false if Path is adequate to reinvoke the tool.
+  // This is useful if realpath is ever called on Path, in which case it will
+  // point to the llvm-driver executable, where PrependArg will be needed to
+  // invoke the correct tool.
+  bool NeedsPrependArg;
+};
 
 } // namespace llvm
 

diff  --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp
index 152d902f52e67..d08d451b5a4e8 100644
--- a/llvm/lib/Support/Path.cpp
+++ b/llvm/lib/Support/Path.cpp
@@ -1202,18 +1202,10 @@ Error readNativeFileToEOF(file_t FileHandle, SmallVectorImpl<char> &Buffer,
 #include "Windows/Path.inc"
 #endif
 
-bool IsLLVMDriver = false;
-
 namespace llvm {
 namespace sys {
 namespace fs {
 
-std::string getMainExecutable(const char *Argv0, void *MainAddr) {
-  if (IsLLVMDriver)
-    return sys::path::stem(Argv0).str();
-  return getMainExecutableImpl(Argv0, MainAddr);
-}
-
 TempFile::TempFile(StringRef Name, int FD)
     : TmpName(std::string(Name)), FD(FD) {}
 TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); }

diff  --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 3efcad4f2bed4..e2aece49cbc52 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -190,7 +190,7 @@ static char *getprogpath(char ret[PATH_MAX], const char *bin) {
 
 /// GetMainExecutable - Return the path to the main executable, given the
 /// value of argv[0] from program startup.
-std::string getMainExecutableImpl(const char *argv0, void *MainAddr) {
+std::string getMainExecutable(const char *argv0, void *MainAddr) {
 #if defined(__APPLE__)
   // On OS X the executable path is saved to the stack by dyld. Reading it
   // from there is much faster than calling dladdr, especially for large

diff  --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index 92cf4fcda5a68..45f0e95c87fe4 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -130,7 +130,7 @@ namespace fs {
 
 const file_t kInvalidFile = INVALID_HANDLE_VALUE;
 
-std::string getMainExecutableImpl(const char *argv0, void *MainExecAddr) {
+std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
   SmallVector<wchar_t, MAX_PATH> PathName;
   PathName.resize_for_overwrite(PathName.capacity());
   DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.size());

diff  --git a/llvm/tools/llvm-driver/llvm-driver.cpp b/llvm/tools/llvm-driver/llvm-driver.cpp
index 653c2adee26e5..01c27618945ce 100644
--- a/llvm/tools/llvm-driver/llvm-driver.cpp
+++ b/llvm/tools/llvm-driver/llvm-driver.cpp
@@ -36,7 +36,7 @@ static void printHelpMessage() {
                << "OPTIONS:\n\n  --help - Display this message";
 }
 
-static int findTool(int Argc, char **Argv) {
+static int findTool(int Argc, char **Argv, const char *Argv0) {
   if (!Argc) {
     printHelpMessage();
     return 1;
@@ -62,21 +62,22 @@ static int findTool(int Argc, char **Argv) {
     return false;
   };
 
+  auto MakeDriverArgs = [=]() -> llvm::ToolContext {
+    if (ToolName != Argv0)
+      return {Argv0, ToolName.data(), true};
+    return {Argv0, sys::path::filename(Argv0).data(), false};
+  };
+
 #define LLVM_DRIVER_TOOL(tool, entry)                                          \
   if (Is(tool))                                                                \
-    return entry##_main(Argc, Argv, {});
+    return entry##_main(Argc, Argv, MakeDriverArgs());
 #include "LLVMDriverTools.def"
 
   if (Is("llvm"))
-    return findTool(Argc - 1, Argv + 1);
+    return findTool(Argc - 1, Argv + 1, Argv0);
 
   printHelpMessage();
   return 1;
 }
 
-extern bool IsLLVMDriver;
-
-int main(int Argc, char **Argv) {
-  IsLLVMDriver = true;
-  return findTool(Argc, Argv);
-}
+int main(int Argc, char **Argv) { return findTool(Argc, Argv, Argv[0]); }


        


More information about the llvm-commits mailing list