LCOV - code coverage report
Current view: top level - src - zig_clang_driver.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 106 238 44.5 %
Date: 1970-01-01 00:00:01 Functions: 10 14 71.4 %
Branches: 52 184 28.3 %

           Branch data     Line data    Source code
       1                 :            : //===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
       2                 :            : //
       3                 :            : //                     The LLVM Compiler Infrastructure
       4                 :            : //
       5                 :            : // This file is distributed under the University of Illinois Open Source
       6                 :            : // License. See LICENSE.TXT for details.
       7                 :            : //
       8                 :            : //===----------------------------------------------------------------------===//
       9                 :            : //
      10                 :            : // This is the entry point to the clang driver; it is a thin wrapper
      11                 :            : // for functionality in the Driver clang library.
      12                 :            : //
      13                 :            : //===----------------------------------------------------------------------===//
      14                 :            : 
      15                 :            : #include "clang/Driver/Driver.h"
      16                 :            : #include "clang/Basic/DiagnosticOptions.h"
      17                 :            : #include "clang/Driver/Compilation.h"
      18                 :            : #include "clang/Driver/DriverDiagnostic.h"
      19                 :            : #include "clang/Driver/Options.h"
      20                 :            : #include "clang/Driver/ToolChain.h"
      21                 :            : #include "clang/Frontend/ChainedDiagnosticConsumer.h"
      22                 :            : #include "clang/Frontend/CompilerInvocation.h"
      23                 :            : #include "clang/Frontend/SerializedDiagnosticPrinter.h"
      24                 :            : #include "clang/Frontend/TextDiagnosticPrinter.h"
      25                 :            : #include "clang/Frontend/Utils.h"
      26                 :            : #include "llvm/ADT/ArrayRef.h"
      27                 :            : #include "llvm/ADT/SmallString.h"
      28                 :            : #include "llvm/ADT/SmallVector.h"
      29                 :            : #include "llvm/Option/ArgList.h"
      30                 :            : #include "llvm/Option/OptTable.h"
      31                 :            : #include "llvm/Option/Option.h"
      32                 :            : #include "llvm/Support/CommandLine.h"
      33                 :            : #include "llvm/Support/ErrorHandling.h"
      34                 :            : #include "llvm/Support/FileSystem.h"
      35                 :            : #include "llvm/Support/Host.h"
      36                 :            : #include "llvm/Support/InitLLVM.h"
      37                 :            : #include "llvm/Support/Path.h"
      38                 :            : #include "llvm/Support/Process.h"
      39                 :            : #include "llvm/Support/Program.h"
      40                 :            : #include "llvm/Support/Regex.h"
      41                 :            : #include "llvm/Support/Signals.h"
      42                 :            : #include "llvm/Support/StringSaver.h"
      43                 :            : #include "llvm/Support/TargetSelect.h"
      44                 :            : #include "llvm/Support/Timer.h"
      45                 :            : #include "llvm/Support/raw_ostream.h"
      46                 :            : #include <memory>
      47                 :            : #include <set>
      48                 :            : #include <system_error>
      49                 :            : using namespace clang;
      50                 :            : using namespace clang::driver;
      51                 :            : using namespace llvm::opt;
      52                 :            : 
      53                 :         35 : std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
      54         [ -  + ]:         35 :   if (!CanonicalPrefixes) {
      55                 :          0 :     SmallString<128> ExecutablePath(Argv0);
      56                 :            :     // Do a PATH lookup if Argv0 isn't a valid path.
      57         [ #  # ]:          0 :     if (!llvm::sys::fs::exists(ExecutablePath))
      58         [ #  # ]:          0 :       if (llvm::ErrorOr<std::string> P =
      59                 :          0 :               llvm::sys::findProgramByName(ExecutablePath))
      60                 :          0 :         ExecutablePath = *P;
      61                 :          0 :     return ExecutablePath.str();
      62                 :            :   }
      63                 :            : 
      64                 :            :   // This just needs to be some symbol in the binary; C++ doesn't
      65                 :            :   // allow taking the address of ::main however.
      66                 :         35 :   void *P = (void*) (intptr_t) GetExecutablePath;
      67                 :         35 :   return llvm::sys::fs::getMainExecutable(Argv0, P);
      68                 :            : }
      69                 :            : 
      70                 :          0 : static const char *GetStableCStr(std::set<std::string> &SavedStrings,
      71                 :            :                                  StringRef S) {
      72                 :          0 :   return SavedStrings.insert(S).first->c_str();
      73                 :            : }
      74                 :            : 
      75                 :            : /// ApplyQAOverride - Apply a list of edits to the input argument lists.
      76                 :            : ///
      77                 :            : /// The input string is a space separate list of edits to perform,
      78                 :            : /// they are applied in order to the input argument lists. Edits
      79                 :            : /// should be one of the following forms:
      80                 :            : ///
      81                 :            : ///  '#': Silence information about the changes to the command line arguments.
      82                 :            : ///
      83                 :            : ///  '^': Add FOO as a new argument at the beginning of the command line.
      84                 :            : ///
      85                 :            : ///  '+': Add FOO as a new argument at the end of the command line.
      86                 :            : ///
      87                 :            : ///  's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
      88                 :            : ///  line.
      89                 :            : ///
      90                 :            : ///  'xOPTION': Removes all instances of the literal argument OPTION.
      91                 :            : ///
      92                 :            : ///  'XOPTION': Removes all instances of the literal argument OPTION,
      93                 :            : ///  and the following argument.
      94                 :            : ///
      95                 :            : ///  'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
      96                 :            : ///  at the end of the command line.
      97                 :            : ///
      98                 :            : /// \param OS - The stream to write edit information to.
      99                 :            : /// \param Args - The vector of command line arguments.
     100                 :            : /// \param Edit - The override command to perform.
     101                 :            : /// \param SavedStrings - Set to use for storing string representations.
     102                 :          0 : static void ApplyOneQAOverride(raw_ostream &OS,
     103                 :            :                                SmallVectorImpl<const char*> &Args,
     104                 :            :                                StringRef Edit,
     105                 :            :                                std::set<std::string> &SavedStrings) {
     106                 :            :   // This does not need to be efficient.
     107                 :            : 
     108         [ #  # ]:          0 :   if (Edit[0] == '^') {
     109                 :            :     const char *Str =
     110                 :          0 :       GetStableCStr(SavedStrings, Edit.substr(1));
     111                 :          0 :     OS << "### Adding argument " << Str << " at beginning\n";
     112                 :          0 :     Args.insert(Args.begin() + 1, Str);
     113         [ #  # ]:          0 :   } else if (Edit[0] == '+') {
     114                 :            :     const char *Str =
     115                 :          0 :       GetStableCStr(SavedStrings, Edit.substr(1));
     116                 :          0 :     OS << "### Adding argument " << Str << " at end\n";
     117                 :          0 :     Args.push_back(Str);
     118 [ #  # ][ #  # ]:          0 :   } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
         [ #  # ][ #  # ]
                 [ #  # ]
     119                 :          0 :              Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
     120                 :          0 :     StringRef MatchPattern = Edit.substr(2).split('/').first;
     121                 :          0 :     StringRef ReplPattern = Edit.substr(2).split('/').second;
     122                 :          0 :     ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
     123                 :            : 
     124         [ #  # ]:          0 :     for (unsigned i = 1, e = Args.size(); i != e; ++i) {
     125                 :            :       // Ignore end-of-line response file markers
     126         [ #  # ]:          0 :       if (Args[i] == nullptr)
     127                 :          0 :         continue;
     128                 :          0 :       std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
     129                 :            : 
     130         [ #  # ]:          0 :       if (Repl != Args[i]) {
     131                 :          0 :         OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
     132                 :          0 :         Args[i] = GetStableCStr(SavedStrings, Repl);
     133                 :            :       }
     134                 :            :     }
     135 [ #  # ][ #  # ]:          0 :   } else if (Edit[0] == 'x' || Edit[0] == 'X') {
                 [ #  # ]
     136                 :          0 :     auto Option = Edit.substr(1);
     137         [ #  # ]:          0 :     for (unsigned i = 1; i < Args.size();) {
     138         [ #  # ]:          0 :       if (Option == Args[i]) {
     139                 :          0 :         OS << "### Deleting argument " << Args[i] << '\n';
     140                 :          0 :         Args.erase(Args.begin() + i);
     141         [ #  # ]:          0 :         if (Edit[0] == 'X') {
     142         [ #  # ]:          0 :           if (i < Args.size()) {
     143                 :          0 :             OS << "### Deleting argument " << Args[i] << '\n';
     144                 :          0 :             Args.erase(Args.begin() + i);
     145                 :            :           } else
     146                 :          0 :             OS << "### Invalid X edit, end of command line!\n";
     147                 :            :         }
     148                 :            :       } else
     149                 :          0 :         ++i;
     150                 :            :     }
     151         [ #  # ]:          0 :   } else if (Edit[0] == 'O') {
     152         [ #  # ]:          0 :     for (unsigned i = 1; i < Args.size();) {
     153                 :          0 :       const char *A = Args[i];
     154                 :            :       // Ignore end-of-line response file markers
     155         [ #  # ]:          0 :       if (A == nullptr)
     156                 :          0 :         continue;
     157 [ #  # ][ #  # ]:          0 :       if (A[0] == '-' && A[1] == 'O' &&
                 [ #  # ]
     158         [ #  # ]:          0 :           (A[2] == '\0' ||
     159 [ #  # ][ #  # ]:          0 :            (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
                 [ #  # ]
     160         [ #  # ]:          0 :                              ('0' <= A[2] && A[2] <= '9'))))) {
     161                 :          0 :         OS << "### Deleting argument " << Args[i] << '\n';
     162                 :          0 :         Args.erase(Args.begin() + i);
     163                 :            :       } else
     164                 :          0 :         ++i;
     165                 :            :     }
     166                 :          0 :     OS << "### Adding argument " << Edit << " at end\n";
     167                 :          0 :     Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
     168                 :            :   } else {
     169                 :          0 :     OS << "### Unrecognized edit: " << Edit << "\n";
     170                 :            :   }
     171                 :          0 : }
     172                 :            : 
     173                 :            : /// ApplyQAOverride - Apply a comma separate list of edits to the
     174                 :            : /// input argument lists. See ApplyOneQAOverride.
     175                 :          0 : static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
     176                 :            :                             const char *OverrideStr,
     177                 :            :                             std::set<std::string> &SavedStrings) {
     178                 :          0 :   raw_ostream *OS = &llvm::errs();
     179                 :            : 
     180         [ #  # ]:          0 :   if (OverrideStr[0] == '#') {
     181                 :          0 :     ++OverrideStr;
     182                 :          0 :     OS = &llvm::nulls();
     183                 :            :   }
     184                 :            : 
     185                 :          0 :   *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
     186                 :            : 
     187                 :            :   // This does not need to be efficient.
     188                 :            : 
     189                 :          0 :   const char *S = OverrideStr;
     190         [ #  # ]:          0 :   while (*S) {
     191                 :          0 :     const char *End = ::strchr(S, ' ');
     192         [ #  # ]:          0 :     if (!End)
     193                 :          0 :       End = S + strlen(S);
     194         [ #  # ]:          0 :     if (End != S)
     195                 :          0 :       ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
     196                 :          0 :     S = End;
     197         [ #  # ]:          0 :     if (*S != '\0')
     198                 :          0 :       ++S;
     199                 :            :   }
     200                 :          0 : }
     201                 :            : 
     202                 :            : extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
     203                 :            :                     void *MainAddr);
     204                 :            : extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
     205                 :            :                       void *MainAddr);
     206                 :            : 
     207                 :         35 : static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
     208                 :            :                                     SmallVectorImpl<const char *> &ArgVector,
     209                 :            :                                     std::set<std::string> &SavedStrings) {
     210                 :            :   // Put target and mode arguments at the start of argument list so that
     211                 :            :   // arguments specified in command line could override them. Avoid putting
     212                 :            :   // them at index 0, as an option like '-cc1' must remain the first.
     213                 :         35 :   int InsertionPoint = 0;
     214         [ +  - ]:         35 :   if (ArgVector.size() > 0)
     215                 :         35 :     ++InsertionPoint;
     216                 :            : 
     217         [ -  + ]:         35 :   if (NameParts.DriverMode) {
     218                 :            :     // Add the mode flag to the arguments.
     219                 :          0 :     ArgVector.insert(ArgVector.begin() + InsertionPoint,
     220                 :          0 :                      GetStableCStr(SavedStrings, NameParts.DriverMode));
     221                 :            :   }
     222                 :            : 
     223         [ -  + ]:         35 :   if (NameParts.TargetIsValid) {
     224                 :          0 :     const char *arr[] = {"-target", GetStableCStr(SavedStrings,
     225                 :          0 :                                                   NameParts.TargetPrefix)};
     226                 :          0 :     ArgVector.insert(ArgVector.begin() + InsertionPoint,
     227                 :            :                      std::begin(arr), std::end(arr));
     228                 :            :   }
     229                 :         35 : }
     230                 :            : 
     231                 :          0 : static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
     232                 :            :                                SmallVectorImpl<const char *> &Opts) {
     233                 :          0 :   llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
     234                 :            :   // The first instance of '#' should be replaced with '=' in each option.
     235         [ #  # ]:          0 :   for (const char *Opt : Opts)
     236         [ #  # ]:          0 :     if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#')))
     237                 :          0 :       *NumberSignPtr = '=';
     238                 :          0 : }
     239                 :            : 
     240                 :         35 : static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
     241                 :            :   // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
     242                 :         35 :   TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
     243         [ -  + ]:         35 :   if (TheDriver.CCPrintOptions)
     244                 :          0 :     TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
     245                 :            : 
     246                 :            :   // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
     247                 :         35 :   TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
     248         [ -  + ]:         35 :   if (TheDriver.CCPrintHeaders)
     249                 :          0 :     TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
     250                 :            : 
     251                 :            :   // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
     252                 :         35 :   TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
     253         [ -  + ]:         35 :   if (TheDriver.CCLogDiagnostics)
     254                 :          0 :     TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
     255                 :         35 : }
     256                 :            : 
     257                 :         35 : static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
     258                 :            :                                    const std::string &Path) {
     259                 :            :   // If the clang binary happens to be named cl.exe for compatibility reasons,
     260                 :            :   // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
     261                 :         35 :   StringRef ExeBasename(llvm::sys::path::stem(Path));
     262         [ -  + ]:         35 :   if (ExeBasename.equals_lower("cl"))
     263                 :          0 :     ExeBasename = "clang-cl";
     264                 :         35 :   DiagClient->setPrefix(ExeBasename);
     265                 :         35 : }
     266                 :            : 
     267                 :            : // This lets us create the DiagnosticsEngine with a properly-filled-out
     268                 :            : // DiagnosticOptions instance.
     269                 :            : static DiagnosticOptions *
     270                 :         35 : CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) {
     271                 :         35 :   auto *DiagOpts = new DiagnosticOptions;
     272                 :         70 :   std::unique_ptr<OptTable> Opts(createDriverOptTable());
     273                 :            :   unsigned MissingArgIndex, MissingArgCount;
     274                 :            :   InputArgList Args =
     275                 :         70 :       Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount);
     276                 :            :   // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
     277                 :            :   // Any errors that would be diagnosed here will also be diagnosed later,
     278                 :            :   // when the DiagnosticsEngine actually exists.
     279                 :         35 :   (void)ParseDiagnosticArgs(*DiagOpts, Args);
     280                 :         70 :   return DiagOpts;
     281                 :            : }
     282                 :            : 
     283                 :         35 : static void SetInstallDir(SmallVectorImpl<const char *> &argv,
     284                 :            :                           Driver &TheDriver, bool CanonicalPrefixes) {
     285                 :            :   // Attempt to find the original path used to invoke the driver, to determine
     286                 :            :   // the installed path. We do this manually, because we want to support that
     287                 :            :   // path being a symlink.
     288                 :         70 :   SmallString<128> InstalledPath(argv[0]);
     289                 :            : 
     290                 :            :   // Do a PATH lookup, if there are no directory components.
     291         [ +  - ]:         70 :   if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
     292         [ +  - ]:         35 :     if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
     293                 :         70 :             llvm::sys::path::filename(InstalledPath.str())))
     294                 :         70 :       InstalledPath = *Tmp;
     295                 :            : 
     296                 :            :   // FIXME: We don't actually canonicalize this, we just make it absolute.
     297         [ +  - ]:         35 :   if (CanonicalPrefixes)
     298                 :         35 :     llvm::sys::fs::make_absolute(InstalledPath);
     299                 :            : 
     300                 :         35 :   StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
     301         [ +  - ]:         35 :   if (llvm::sys::fs::exists(InstalledPathParent))
     302                 :         35 :     TheDriver.setInstalledDir(InstalledPathParent);
     303                 :         35 : }
     304                 :            : 
     305                 :         43 : static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
     306                 :         43 :   void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
     307         [ +  + ]:         43 :   if (Tool == "")
     308                 :         35 :     return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
     309         [ +  - ]:          8 :   if (Tool == "as")
     310                 :          8 :     return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
     311                 :            : 
     312                 :            :   // Reject unknown tools.
     313                 :          0 :   llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
     314                 :          0 :                << "Valid tools include '-cc1' and '-cc1as'.\n";
     315                 :          0 :   return 1;
     316                 :            : }
     317                 :            : 
     318                 :            : extern "C" int ZigClang_main(int argc_, const char **argv_);
     319                 :         78 : int ZigClang_main(int argc_, const char **argv_) {
     320                 :        156 :   llvm::InitLLVM X(argc_, argv_);
     321 [ +  + ][ +  + ]:         78 :   size_t argv_offset = (strcmp(argv_[1], "-cc1") == 0 || strcmp(argv_[1], "-cc1as") == 0) ? 0 : 1;
     322                 :        156 :   SmallVector<const char *, 256> argv(argv_ + argv_offset, argv_ + argc_);
     323                 :            : 
     324         [ -  + ]:         78 :   if (llvm::sys::Process::FixupStandardFileDescriptors())
     325                 :          0 :     return 1;
     326                 :            : 
     327                 :         78 :   llvm::InitializeAllTargets();
     328                 :        156 :   auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
     329                 :            : 
     330                 :        156 :   llvm::BumpPtrAllocator A;
     331                 :         78 :   llvm::StringSaver Saver(A);
     332                 :            : 
     333                 :            :   // Parse response files using the GNU syntax, unless we're in CL mode. There
     334                 :            :   // are two ways to put clang in CL compatibility mode: argv[0] is either
     335                 :            :   // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
     336                 :            :   // command line parsing can't happen until after response file parsing, so we
     337                 :            :   // have to manually search for a --driver-mode=cl argument the hard way.
     338                 :            :   // Finally, our -cc1 tools don't care which tokenization mode we use because
     339                 :            :   // response files written by clang will tokenize the same way in either mode.
     340                 :         78 :   bool ClangCLMode = false;
     341 [ +  - ][ -  + ]:        156 :   if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
                 [ -  + ]
     342                 :      12488 :       std::find_if(argv.begin(), argv.end(), [](const char *F) {
     343 [ +  - ][ -  + ]:      12410 :         return F && strcmp(F, "--driver-mode=cl") == 0;
     344                 :      12410 :       }) != argv.end()) {
     345                 :          0 :     ClangCLMode = true;
     346                 :            :   }
     347                 :         78 :   enum { Default, POSIX, Windows } RSPQuoting = Default;
     348         [ +  + ]:      12488 :   for (const char *F : argv) {
     349         [ -  + ]:      12410 :     if (strcmp(F, "--rsp-quoting=posix") == 0)
     350                 :          0 :       RSPQuoting = POSIX;
     351         [ -  + ]:      12410 :     else if (strcmp(F, "--rsp-quoting=windows") == 0)
     352                 :          0 :       RSPQuoting = Windows;
     353                 :            :   }
     354                 :            : 
     355                 :            :   // Determines whether we want nullptr markers in argv to indicate response
     356                 :            :   // files end-of-lines. We only use this for the /LINK driver argument with
     357                 :            :   // clang-cl.exe on Windows.
     358                 :         78 :   bool MarkEOLs = ClangCLMode;
     359                 :            : 
     360                 :            :   llvm::cl::TokenizerCallback Tokenizer;
     361 [ +  - ][ +  - ]:         78 :   if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
                 [ -  + ]
     362                 :          0 :     Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
     363                 :            :   else
     364                 :         78 :     Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
     365                 :            : 
     366 [ -  + ][ #  # ]:         78 :   if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
         [ #  # ][ -  + ]
     367                 :          0 :     MarkEOLs = false;
     368                 :         78 :   llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs);
     369                 :            : 
     370                 :            :   // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
     371                 :            :   // file.
     372                 :        234 :   auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
     373                 :        234 :                                [](const char *A) { return A != nullptr; });
     374 [ +  - ][ +  + ]:        156 :   if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
                 [ +  + ]
     375                 :            :     // If -cc1 came from a response file, remove the EOL sentinels.
     376         [ -  + ]:         43 :     if (MarkEOLs) {
     377                 :          0 :       auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
     378                 :          0 :       argv.resize(newEnd - argv.begin());
     379                 :            :     }
     380                 :         43 :     return ExecuteCC1Tool(argv, argv[1] + 4);
     381                 :            :   }
     382                 :            : 
     383                 :         35 :   bool CanonicalPrefixes = true;
     384         [ +  + ]:       2078 :   for (int i = 1, size = argv.size(); i < size; ++i) {
     385                 :            :     // Skip end-of-line response file markers
     386         [ -  + ]:       2043 :     if (argv[i] == nullptr)
     387                 :          0 :       continue;
     388         [ -  + ]:       2043 :     if (StringRef(argv[i]) == "-no-canonical-prefixes") {
     389                 :          0 :       CanonicalPrefixes = false;
     390                 :          0 :       break;
     391                 :            :     }
     392                 :            :   }
     393                 :            : 
     394                 :            :   // Handle CL and _CL_ which permits additional command line options to be
     395                 :            :   // prepended or appended.
     396         [ -  + ]:         35 :   if (ClangCLMode) {
     397                 :            :     // Arguments in "CL" are prepended.
     398                 :          0 :     llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
     399         [ #  # ]:          0 :     if (OptCL.hasValue()) {
     400                 :          0 :       SmallVector<const char *, 8> PrependedOpts;
     401                 :          0 :       getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
     402                 :            : 
     403                 :            :       // Insert right after the program name to prepend to the argument list.
     404                 :          0 :       argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
     405                 :            :     }
     406                 :            :     // Arguments in "_CL_" are appended.
     407                 :          0 :     llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
     408         [ #  # ]:          0 :     if (Opt_CL_.hasValue()) {
     409                 :          0 :       SmallVector<const char *, 8> AppendedOpts;
     410                 :          0 :       getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
     411                 :            : 
     412                 :            :       // Insert at the end of the argument list to append.
     413                 :          0 :       argv.append(AppendedOpts.begin(), AppendedOpts.end());
     414                 :            :     }
     415                 :            :   }
     416                 :            : 
     417                 :         70 :   std::set<std::string> SavedStrings;
     418                 :            :   // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
     419                 :            :   // scenes.
     420         [ -  + ]:         35 :   if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
     421                 :            :     // FIXME: Driver shouldn't take extra initial argument.
     422                 :          0 :     ApplyQAOverride(argv, OverrideStr, SavedStrings);
     423                 :            :   }
     424                 :            : 
     425                 :         70 :   std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
     426                 :            : 
     427                 :            :   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
     428                 :         70 :       CreateAndPopulateDiagOpts(argv);
     429                 :            : 
     430                 :            :   TextDiagnosticPrinter *DiagClient
     431                 :         35 :     = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
     432                 :         35 :   FixupDiagPrefixExeName(DiagClient, Path);
     433                 :            : 
     434                 :         70 :   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
     435                 :            : 
     436                 :         70 :   DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
     437                 :            : 
     438         [ -  + ]:         35 :   if (!DiagOpts->DiagnosticSerializationFile.empty()) {
     439                 :            :     auto SerializedConsumer =
     440                 :          0 :         clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
     441                 :          0 :                                         &*DiagOpts, /*MergeChildRecords=*/true);
     442                 :          0 :     Diags.setClient(new ChainedDiagnosticConsumer(
     443                 :          0 :         Diags.takeClient(), std::move(SerializedConsumer)));
     444                 :            :   }
     445                 :            : 
     446                 :         35 :   ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
     447                 :            : 
     448                 :        105 :   Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
     449                 :         35 :   SetInstallDir(argv, TheDriver, CanonicalPrefixes);
     450                 :         35 :   TheDriver.setTargetAndMode(TargetAndMode);
     451                 :            : 
     452                 :         35 :   insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
     453                 :            : 
     454                 :         35 :   SetBackdoorDriverOutputsFromEnvVars(TheDriver);
     455                 :            : 
     456                 :         70 :   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
     457                 :         35 :   int Res = 1;
     458 [ +  - ][ +  - ]:         35 :   if (C && !C->containsError()) {
                 [ +  - ]
     459                 :         70 :     SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
     460                 :         35 :     Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
     461                 :            : 
     462                 :            :     // Force a crash to test the diagnostics.
     463         [ -  + ]:         35 :     if (TheDriver.GenReproducer) {
     464                 :          0 :       Diags.Report(diag::err_drv_force_crash)
     465                 :          0 :         << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
     466                 :            : 
     467                 :            :       // Pretend that every command failed.
     468                 :          0 :       FailingCommands.clear();
     469         [ #  # ]:          0 :       for (const auto &J : C->getJobs())
     470         [ #  # ]:          0 :         if (const Command *C = dyn_cast<Command>(&J))
     471                 :          0 :           FailingCommands.push_back(std::make_pair(-1, C));
     472                 :            :     }
     473                 :            : 
     474         [ -  + ]:         35 :     for (const auto &P : FailingCommands) {
     475                 :          0 :       int CommandRes = P.first;
     476                 :          0 :       const Command *FailingCommand = P.second;
     477         [ #  # ]:          0 :       if (!Res)
     478                 :          0 :         Res = CommandRes;
     479                 :            : 
     480                 :            :       // If result status is < 0, then the driver command signalled an error.
     481                 :            :       // If result status is 70, then the driver command reported a fatal error.
     482                 :            :       // On Windows, abort will return an exit code of 3.  In these cases,
     483                 :            :       // generate additional diagnostic information if possible.
     484 [ #  # ][ #  # ]:          0 :       bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
     485                 :            : #ifdef _WIN32
     486                 :            :       DiagnoseCrash |= CommandRes == 3;
     487                 :            : #endif
     488         [ #  # ]:          0 :       if (DiagnoseCrash) {
     489                 :          0 :         TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
     490                 :          0 :         break;
     491                 :            :       }
     492                 :            :     }
     493                 :            :   }
     494                 :            : 
     495                 :         35 :   Diags.getClient()->finish();
     496                 :            : 
     497                 :            :   // If any timers were active but haven't been destroyed yet, print their
     498                 :            :   // results now.  This happens in -disable-free mode.
     499                 :         35 :   llvm::TimerGroup::printAll(llvm::errs());
     500                 :            : 
     501                 :            : #ifdef _WIN32
     502                 :            :   // Exit status should not be negative on Win32, unless abnormal termination.
     503                 :            :   // Once abnormal termiation was caught, negative status should not be
     504                 :            :   // propagated.
     505                 :            :   if (Res < 0)
     506                 :            :     Res = 1;
     507                 :            : #endif
     508                 :            : 
     509                 :            :   // If we have multiple failing commands, we return the result of the first
     510                 :            :   // failing command.
     511                 :         35 :   return Res;
     512                 :            : }
     513                 :            : 

Generated by: LCOV version 1.14