/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/Job.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Job.cpp - Command to Execute ---------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "clang/Driver/Job.h" |
10 | | #include "InputInfo.h" |
11 | | #include "clang/Basic/LLVM.h" |
12 | | #include "clang/Driver/Driver.h" |
13 | | #include "clang/Driver/DriverDiagnostic.h" |
14 | | #include "clang/Driver/Tool.h" |
15 | | #include "clang/Driver/ToolChain.h" |
16 | | #include "llvm/ADT/ArrayRef.h" |
17 | | #include "llvm/ADT/SmallString.h" |
18 | | #include "llvm/ADT/SmallVector.h" |
19 | | #include "llvm/ADT/StringRef.h" |
20 | | #include "llvm/ADT/StringSet.h" |
21 | | #include "llvm/ADT/StringSwitch.h" |
22 | | #include "llvm/Support/CrashRecoveryContext.h" |
23 | | #include "llvm/Support/FileSystem.h" |
24 | | #include "llvm/Support/Path.h" |
25 | | #include "llvm/Support/PrettyStackTrace.h" |
26 | | #include "llvm/Support/Program.h" |
27 | | #include "llvm/Support/raw_ostream.h" |
28 | | #include <algorithm> |
29 | | #include <cassert> |
30 | | #include <cstddef> |
31 | | #include <string> |
32 | | #include <system_error> |
33 | | #include <utility> |
34 | | |
35 | | using namespace clang; |
36 | | using namespace driver; |
37 | | |
38 | | Command::Command(const Action &Source, const Tool &Creator, |
39 | | ResponseFileSupport ResponseSupport, const char *Executable, |
40 | | const llvm::opt::ArgStringList &Arguments, |
41 | | ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs) |
42 | | : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport), |
43 | 50.4k | Executable(Executable), Arguments(Arguments) { |
44 | 50.4k | for (const auto &II : Inputs) |
45 | 52.7k | if (II.isFilename()) |
46 | 51.5k | InputFilenames.push_back(II.getFilename()); |
47 | 50.4k | for (const auto &II : Outputs) |
48 | 50.5k | if (II.isFilename()) |
49 | 22.6k | OutputFilenames.push_back(II.getFilename()); |
50 | 50.4k | } |
51 | | |
52 | | /// Check if the compiler flag in question should be skipped when |
53 | | /// emitting a reproducer. Also track how many arguments it has and if the |
54 | | /// option is some kind of include path. |
55 | | static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, |
56 | 1.53k | bool &IsInclude) { |
57 | 1.53k | SkipNum = 2; |
58 | | // These flags are all of the form -Flag <Arg> and are treated as two |
59 | | // arguments. Therefore, we need to skip the flag and the next argument. |
60 | 1.53k | bool ShouldSkip = llvm::StringSwitch<bool>(Flag) |
61 | 1.53k | .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) |
62 | 1.53k | .Cases("-o", "-dependency-file", true) |
63 | 1.53k | .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) |
64 | 1.53k | .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) |
65 | 1.53k | .Default(false); |
66 | 1.53k | if (ShouldSkip) |
67 | 48 | return true; |
68 | | |
69 | | // Some include flags shouldn't be skipped if we have a crash VFS |
70 | 1.48k | IsInclude = llvm::StringSwitch<bool>(Flag) |
71 | 1.48k | .Cases("-include", "-header-include-file", true) |
72 | 1.48k | .Cases("-idirafter", "-internal-isystem", "-iwithprefix", true) |
73 | 1.48k | .Cases("-internal-externc-isystem", "-iprefix", true) |
74 | 1.48k | .Cases("-iwithprefixbefore", "-isystem", "-iquote", true) |
75 | 1.48k | .Cases("-isysroot", "-I", "-F", "-resource-dir", true) |
76 | 1.48k | .Cases("-iframework", "-include-pch", true) |
77 | 1.48k | .Default(false); |
78 | 1.48k | if (IsInclude) |
79 | 172 | return !HaveCrashVFS; |
80 | | |
81 | | // The remaining flags are treated as a single argument. |
82 | | |
83 | | // These flags are all of the form -Flag and have no second argument. |
84 | 1.31k | ShouldSkip = llvm::StringSwitch<bool>(Flag) |
85 | 1.31k | .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) |
86 | 1.31k | .Case("-MMD", true) |
87 | 1.31k | .Default(false); |
88 | | |
89 | | // Match found. |
90 | 1.31k | SkipNum = 1; |
91 | 1.31k | if (ShouldSkip) |
92 | 0 | return true; |
93 | | |
94 | | // These flags are treated as a single argument (e.g., -F<Dir>). |
95 | 1.31k | StringRef FlagRef(Flag); |
96 | 1.31k | IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I")1.31k ; |
97 | 1.31k | if (IsInclude) |
98 | 7 | return !HaveCrashVFS; |
99 | 1.31k | if (FlagRef.startswith("-fmodules-cache-path=")) |
100 | 14 | return true; |
101 | | |
102 | 1.29k | SkipNum = 0; |
103 | 1.29k | return false; |
104 | 1.29k | } |
105 | | |
106 | 1 | void Command::writeResponseFile(raw_ostream &OS) const { |
107 | | // In a file list, we only write the set of inputs to the response file |
108 | 1 | if (ResponseSupport.ResponseKind == ResponseFileSupport::RF_FileList) { |
109 | 0 | for (const auto *Arg : InputFileList) { |
110 | 0 | OS << Arg << '\n'; |
111 | 0 | } |
112 | 0 | return; |
113 | 0 | } |
114 | | |
115 | | // In regular response files, we send all arguments to the response file. |
116 | | // Wrapping all arguments in double quotes ensures that both Unix tools and |
117 | | // Windows tools understand the response file. |
118 | 600k | for (const auto *Arg : Arguments)1 { |
119 | 600k | OS << '"'; |
120 | | |
121 | 2.40M | for (; *Arg != '\0'; Arg++1.80M ) { |
122 | 1.80M | if (*Arg == '\"' || *Arg == '\\') { |
123 | 0 | OS << '\\'; |
124 | 0 | } |
125 | 1.80M | OS << *Arg; |
126 | 1.80M | } |
127 | | |
128 | 600k | OS << "\" "; |
129 | 600k | } |
130 | 1 | } |
131 | | |
132 | | void Command::buildArgvForResponseFile( |
133 | 1 | llvm::SmallVectorImpl<const char *> &Out) const { |
134 | | // When not a file list, all arguments are sent to the response file. |
135 | | // This leaves us to set the argv to a single parameter, requesting the tool |
136 | | // to read the response file. |
137 | 1 | if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList) { |
138 | 1 | Out.push_back(Executable); |
139 | 1 | Out.push_back(ResponseFileFlag.c_str()); |
140 | 1 | return; |
141 | 1 | } |
142 | | |
143 | 0 | llvm::StringSet<> Inputs; |
144 | 0 | for (const auto *InputName : InputFileList) |
145 | 0 | Inputs.insert(InputName); |
146 | 0 | Out.push_back(Executable); |
147 | | // In a file list, build args vector ignoring parameters that will go in the |
148 | | // response file (elements of the InputFileList vector) |
149 | 0 | bool FirstInput = true; |
150 | 0 | for (const auto *Arg : Arguments) { |
151 | 0 | if (Inputs.count(Arg) == 0) { |
152 | 0 | Out.push_back(Arg); |
153 | 0 | } else if (FirstInput) { |
154 | 0 | FirstInput = false; |
155 | 0 | Out.push_back(ResponseSupport.ResponseFlag); |
156 | 0 | Out.push_back(ResponseFile); |
157 | 0 | } |
158 | 0 | } |
159 | 0 | } |
160 | | |
161 | | /// Rewrite relative include-like flag paths to absolute ones. |
162 | | static void |
163 | | rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx, |
164 | | size_t NumArgs, |
165 | 69 | llvm::SmallVectorImpl<llvm::SmallString<128>> &IncFlags) { |
166 | 69 | using namespace llvm; |
167 | 69 | using namespace sys; |
168 | | |
169 | 69 | auto getAbsPath = [](StringRef InInc, SmallVectorImpl<char> &OutInc) -> bool { |
170 | 69 | if (path::is_absolute(InInc)) // Nothing to do here... |
171 | 68 | return false; |
172 | 1 | std::error_code EC = fs::current_path(OutInc); |
173 | 1 | if (EC) |
174 | 0 | return false; |
175 | 1 | path::append(OutInc, InInc); |
176 | 1 | return true; |
177 | 1 | }; |
178 | | |
179 | 69 | SmallString<128> NewInc; |
180 | 69 | if (NumArgs == 1) { |
181 | 2 | StringRef FlagRef(Args[Idx + NumArgs - 1]); |
182 | 2 | assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) && |
183 | 2 | "Expecting -I or -F"); |
184 | 2 | StringRef Inc = FlagRef.slice(2, StringRef::npos); |
185 | 2 | if (getAbsPath(Inc, NewInc)) { |
186 | 0 | SmallString<128> NewArg(FlagRef.slice(0, 2)); |
187 | 0 | NewArg += NewInc; |
188 | 0 | IncFlags.push_back(std::move(NewArg)); |
189 | 0 | } |
190 | 2 | return; |
191 | 2 | } |
192 | | |
193 | 67 | assert(NumArgs == 2 && "Not expecting more than two arguments"); |
194 | 67 | StringRef Inc(Args[Idx + NumArgs - 1]); |
195 | 67 | if (!getAbsPath(Inc, NewInc)) |
196 | 66 | return; |
197 | 1 | IncFlags.push_back(SmallString<128>(Args[Idx])); |
198 | 1 | IncFlags.push_back(std::move(NewInc)); |
199 | 1 | } |
200 | | |
201 | | void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, |
202 | 14.4k | CrashReportInfo *CrashInfo) const { |
203 | | // Always quote the exe. |
204 | 14.4k | OS << ' '; |
205 | 14.4k | llvm::sys::printArg(OS, Executable, /*Quote=*/true); |
206 | | |
207 | 14.4k | ArrayRef<const char *> Args = Arguments; |
208 | 14.4k | SmallVector<const char *, 128> ArgsRespFile; |
209 | 14.4k | if (ResponseFile != nullptr) { |
210 | 1 | buildArgvForResponseFile(ArgsRespFile); |
211 | 1 | Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name |
212 | 1 | } |
213 | | |
214 | 14.4k | bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty()27 ; |
215 | 606k | for (size_t i = 0, e = Args.size(); i < e; ++i592k ) { |
216 | 592k | const char *const Arg = Args[i]; |
217 | | |
218 | 592k | if (CrashInfo) { |
219 | 1.53k | int NumArgs = 0; |
220 | 1.53k | bool IsInclude = false; |
221 | 1.53k | if (skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) { |
222 | 172 | i += NumArgs - 1; |
223 | 172 | continue; |
224 | 172 | } |
225 | | |
226 | | // Relative includes need to be expanded to absolute paths. |
227 | 1.36k | if (HaveCrashVFS && IsInclude789 ) { |
228 | 69 | SmallVector<SmallString<128>, 2> NewIncFlags; |
229 | 69 | rewriteIncludes(Args, i, NumArgs, NewIncFlags); |
230 | 69 | if (!NewIncFlags.empty()) { |
231 | 2 | for (auto &F : NewIncFlags) { |
232 | 2 | OS << ' '; |
233 | 2 | llvm::sys::printArg(OS, F.c_str(), Quote); |
234 | 2 | } |
235 | 1 | i += NumArgs - 1; |
236 | 1 | continue; |
237 | 1 | } |
238 | 1.36k | } |
239 | | |
240 | 1.36k | auto Found = llvm::find_if(InputFilenames, |
241 | 1.36k | [&Arg](StringRef IF) { return IF == Arg; }); |
242 | 1.36k | if (Found != InputFilenames.end() && |
243 | 27 | (i == 0 || StringRef(Args[i - 1]) != "-main-file-name")) { |
244 | | // Replace the input file name with the crashinfo's file name. |
245 | 27 | OS << ' '; |
246 | 27 | StringRef ShortName = llvm::sys::path::filename(CrashInfo->Filename); |
247 | 27 | llvm::sys::printArg(OS, ShortName.str(), Quote); |
248 | 27 | continue; |
249 | 27 | } |
250 | 592k | } |
251 | | |
252 | 592k | OS << ' '; |
253 | 592k | llvm::sys::printArg(OS, Arg, Quote); |
254 | 592k | } |
255 | | |
256 | 14.4k | if (CrashInfo && HaveCrashVFS27 ) { |
257 | 14 | OS << ' '; |
258 | 14 | llvm::sys::printArg(OS, "-ivfsoverlay", Quote); |
259 | 14 | OS << ' '; |
260 | 14 | llvm::sys::printArg(OS, CrashInfo->VFSPath.str(), Quote); |
261 | | |
262 | | // The leftover modules from the crash are stored in |
263 | | // <name>.cache/vfs/modules |
264 | | // Leave it untouched for pcm inspection and provide a clean/empty dir |
265 | | // path to contain the future generated module cache: |
266 | | // <name>.cache/vfs/repro-modules |
267 | 14 | SmallString<128> RelModCacheDir = llvm::sys::path::parent_path( |
268 | 14 | llvm::sys::path::parent_path(CrashInfo->VFSPath)); |
269 | 14 | llvm::sys::path::append(RelModCacheDir, "repro-modules"); |
270 | | |
271 | 14 | std::string ModCachePath = "-fmodules-cache-path="; |
272 | 14 | ModCachePath.append(RelModCacheDir.c_str()); |
273 | | |
274 | 14 | OS << ' '; |
275 | 14 | llvm::sys::printArg(OS, ModCachePath, Quote); |
276 | 14 | } |
277 | | |
278 | 14.4k | if (ResponseFile != nullptr) { |
279 | 1 | OS << "\n Arguments passed via response file:\n"; |
280 | 1 | writeResponseFile(OS); |
281 | | // Avoiding duplicated newline terminator, since FileLists are |
282 | | // newline-separated. |
283 | 1 | if (ResponseSupport.ResponseKind != ResponseFileSupport::RF_FileList) |
284 | 1 | OS << "\n"; |
285 | 1 | OS << " (end of response file)"; |
286 | 1 | } |
287 | | |
288 | 14.4k | OS << Terminator; |
289 | 14.4k | } |
290 | | |
291 | 1 | void Command::setResponseFile(const char *FileName) { |
292 | 1 | ResponseFile = FileName; |
293 | 1 | ResponseFileFlag = ResponseSupport.ResponseFlag; |
294 | 1 | ResponseFileFlag += FileName; |
295 | 1 | } |
296 | | |
297 | 0 | void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { |
298 | 0 | Environment.reserve(NewEnvironment.size() + 1); |
299 | 0 | Environment.assign(NewEnvironment.begin(), NewEnvironment.end()); |
300 | 0 | Environment.push_back(nullptr); |
301 | 0 | } |
302 | | |
303 | 8.47k | void Command::PrintFileNames() const { |
304 | 8.47k | if (PrintInputFilenames) { |
305 | 4 | for (const char *Arg : InputFilenames) |
306 | 4 | llvm::outs() << llvm::sys::path::filename(Arg) << "\n"; |
307 | 4 | llvm::outs().flush(); |
308 | 4 | } |
309 | 8.47k | } |
310 | | |
311 | | int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, |
312 | 3.26k | std::string *ErrMsg, bool *ExecutionFailed) const { |
313 | 3.26k | PrintFileNames(); |
314 | | |
315 | 3.26k | SmallVector<const char *, 128> Argv; |
316 | 3.26k | if (ResponseFile == nullptr) { |
317 | 3.26k | Argv.push_back(Executable); |
318 | 3.26k | Argv.append(Arguments.begin(), Arguments.end()); |
319 | 3.26k | Argv.push_back(nullptr); |
320 | 0 | } else { |
321 | | // If the command is too large, we need to put arguments in a response file. |
322 | 0 | std::string RespContents; |
323 | 0 | llvm::raw_string_ostream SS(RespContents); |
324 | | |
325 | | // Write file contents and build the Argv vector |
326 | 0 | writeResponseFile(SS); |
327 | 0 | buildArgvForResponseFile(Argv); |
328 | 0 | Argv.push_back(nullptr); |
329 | 0 | SS.flush(); |
330 | | |
331 | | // Save the response file in the appropriate encoding |
332 | 0 | if (std::error_code EC = writeFileWithEncoding( |
333 | 0 | ResponseFile, RespContents, ResponseSupport.ResponseEncoding)) { |
334 | 0 | if (ErrMsg) |
335 | 0 | *ErrMsg = EC.message(); |
336 | 0 | if (ExecutionFailed) |
337 | 0 | *ExecutionFailed = true; |
338 | | // Return -1 by convention (see llvm/include/llvm/Support/Program.h) to |
339 | | // indicate the requested executable cannot be started. |
340 | 0 | return -1; |
341 | 0 | } |
342 | 3.26k | } |
343 | | |
344 | 3.26k | Optional<ArrayRef<StringRef>> Env; |
345 | 3.26k | std::vector<StringRef> ArgvVectorStorage; |
346 | 3.26k | if (!Environment.empty()) { |
347 | 0 | assert(Environment.back() == nullptr && |
348 | 0 | "Environment vector should be null-terminated by now"); |
349 | 0 | ArgvVectorStorage = llvm::toStringRefArray(Environment.data()); |
350 | 0 | Env = makeArrayRef(ArgvVectorStorage); |
351 | 0 | } |
352 | | |
353 | 3.26k | auto Args = llvm::toStringRefArray(Argv.data()); |
354 | 3.26k | return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, |
355 | 3.26k | /*secondsToWait*/ 0, /*memoryLimit*/ 0, |
356 | 3.26k | ErrMsg, ExecutionFailed, &ProcStat); |
357 | 3.26k | } |
358 | | |
359 | | CC1Command::CC1Command(const Action &Source, const Tool &Creator, |
360 | | ResponseFileSupport ResponseSupport, |
361 | | const char *Executable, |
362 | | const llvm::opt::ArgStringList &Arguments, |
363 | | ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs) |
364 | | : Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs, |
365 | 14.5k | Outputs) { |
366 | 14.5k | InProcess = true; |
367 | 14.5k | } |
368 | | |
369 | | void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, |
370 | 8.99k | CrashReportInfo *CrashInfo) const { |
371 | 8.99k | if (InProcess) |
372 | 3.86k | OS << " (in-process)\n"; |
373 | 8.99k | Command::Print(OS, Terminator, Quote, CrashInfo); |
374 | 8.99k | } |
375 | | |
376 | | int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, |
377 | 5.48k | std::string *ErrMsg, bool *ExecutionFailed) const { |
378 | | // FIXME: Currently, if there're more than one job, we disable |
379 | | // -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to |
380 | | // out-of-process execution. See discussion in https://reviews.llvm.org/D74447 |
381 | 5.48k | if (!InProcess) |
382 | 280 | return Command::Execute(Redirects, ErrMsg, ExecutionFailed); |
383 | | |
384 | 5.20k | PrintFileNames(); |
385 | | |
386 | 5.20k | SmallVector<const char *, 128> Argv; |
387 | 5.20k | Argv.push_back(getExecutable()); |
388 | 5.20k | Argv.append(getArguments().begin(), getArguments().end()); |
389 | 5.20k | Argv.push_back(nullptr); |
390 | | |
391 | | // This flag simply indicates that the program couldn't start, which isn't |
392 | | // applicable here. |
393 | 5.20k | if (ExecutionFailed) |
394 | 5.20k | *ExecutionFailed = false; |
395 | | |
396 | 5.20k | llvm::CrashRecoveryContext CRC; |
397 | 5.20k | CRC.DumpStackAndCleanupOnFailure = true; |
398 | | |
399 | 5.20k | const void *PrettyState = llvm::SavePrettyStackState(); |
400 | 5.20k | const Driver &D = getCreator().getToolChain().getDriver(); |
401 | | |
402 | 5.20k | int R = 0; |
403 | | // Enter ExecuteCC1Tool() instead of starting up a new process |
404 | 5.20k | if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) { |
405 | 10 | llvm::RestorePrettyStackState(PrettyState); |
406 | 10 | return CRC.RetCode; |
407 | 10 | } |
408 | 5.19k | return R; |
409 | 5.19k | } |
410 | | |
411 | 0 | void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { |
412 | | // We don't support set a new environment when calling into ExecuteCC1Tool() |
413 | 0 | llvm_unreachable( |
414 | 0 | "The CC1Command doesn't support changing the environment vars!"); |
415 | 0 | } |
416 | | |
417 | | FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, |
418 | | ResponseFileSupport ResponseSupport, |
419 | | const char *Executable_, |
420 | | const llvm::opt::ArgStringList &Arguments_, |
421 | | ArrayRef<InputInfo> Inputs, |
422 | | ArrayRef<InputInfo> Outputs, |
423 | | std::unique_ptr<Command> Fallback_) |
424 | | : Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_, |
425 | | Inputs, Outputs), |
426 | 15 | Fallback(std::move(Fallback_)) {} |
427 | | |
428 | | void FallbackCommand::Print(raw_ostream &OS, const char *Terminator, |
429 | 14 | bool Quote, CrashReportInfo *CrashInfo) const { |
430 | 14 | Command::Print(OS, "", Quote, CrashInfo); |
431 | 14 | OS << " ||"; |
432 | 14 | Fallback->Print(OS, Terminator, Quote, CrashInfo); |
433 | 14 | } |
434 | | |
435 | 1 | static bool ShouldFallback(int ExitCode) { |
436 | | // FIXME: We really just want to fall back for internal errors, such |
437 | | // as when some symbol cannot be mangled, when we should be able to |
438 | | // parse something but can't, etc. |
439 | 1 | return ExitCode != 0; |
440 | 1 | } |
441 | | |
442 | | int FallbackCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, |
443 | 1 | std::string *ErrMsg, bool *ExecutionFailed) const { |
444 | 1 | int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed); |
445 | 1 | if (!ShouldFallback(PrimaryStatus)) |
446 | 0 | return PrimaryStatus; |
447 | | |
448 | | // Clear ExecutionFailed and ErrMsg before falling back. |
449 | 1 | if (ErrMsg) |
450 | 1 | ErrMsg->clear(); |
451 | 1 | if (ExecutionFailed) |
452 | 1 | *ExecutionFailed = false; |
453 | | |
454 | 1 | const Driver &D = getCreator().getToolChain().getDriver(); |
455 | 1 | D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable(); |
456 | | |
457 | 1 | int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed); |
458 | 1 | return SecondaryStatus; |
459 | 1 | } |
460 | | |
461 | | ForceSuccessCommand::ForceSuccessCommand( |
462 | | const Action &Source_, const Tool &Creator_, |
463 | | ResponseFileSupport ResponseSupport, const char *Executable_, |
464 | | const llvm::opt::ArgStringList &Arguments_, ArrayRef<InputInfo> Inputs, |
465 | | ArrayRef<InputInfo> Outputs) |
466 | | : Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_, |
467 | 1 | Inputs, Outputs) {} |
468 | | |
469 | | void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator, |
470 | 1 | bool Quote, CrashReportInfo *CrashInfo) const { |
471 | 1 | Command::Print(OS, "", Quote, CrashInfo); |
472 | 1 | OS << " || (exit 0)" << Terminator; |
473 | 1 | } |
474 | | |
475 | | int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, |
476 | | std::string *ErrMsg, |
477 | 0 | bool *ExecutionFailed) const { |
478 | 0 | int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed); |
479 | 0 | (void)Status; |
480 | 0 | if (ExecutionFailed) |
481 | 0 | *ExecutionFailed = false; |
482 | 0 | return 0; |
483 | 0 | } |
484 | | |
485 | | void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, |
486 | 8.19k | CrashReportInfo *CrashInfo) const { |
487 | 8.19k | for (const auto &Job : *this) |
488 | 14.3k | Job.Print(OS, Terminator, Quote, CrashInfo); |
489 | 8.19k | } |
490 | | |
491 | 30 | void JobList::clear() { Jobs.clear(); } |