Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/Driver/Compilation.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- Compilation.cpp - Compilation Task Implementation ------------------===//
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/Compilation.h"
10
#include "clang/Basic/LLVM.h"
11
#include "clang/Driver/Action.h"
12
#include "clang/Driver/Driver.h"
13
#include "clang/Driver/DriverDiagnostic.h"
14
#include "clang/Driver/Job.h"
15
#include "clang/Driver/Options.h"
16
#include "clang/Driver/ToolChain.h"
17
#include "clang/Driver/Util.h"
18
#include "llvm/ADT/None.h"
19
#include "llvm/ADT/STLExtras.h"
20
#include "llvm/ADT/SmallVector.h"
21
#include "llvm/ADT/Triple.h"
22
#include "llvm/Option/ArgList.h"
23
#include "llvm/Option/OptSpecifier.h"
24
#include "llvm/Option/Option.h"
25
#include "llvm/Support/FileSystem.h"
26
#include "llvm/Support/raw_ostream.h"
27
#include <cassert>
28
#include <string>
29
#include <system_error>
30
#include <utility>
31
32
using namespace clang;
33
using namespace driver;
34
using namespace llvm::opt;
35
36
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
37
                         InputArgList *_Args, DerivedArgList *_TranslatedArgs,
38
                         bool ContainsError)
39
    : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
40
30.3k
      TranslatedArgs(_TranslatedArgs), ContainsError(ContainsError) {
41
30.3k
  // The offloading host toolchain is the default toolchain.
42
30.3k
  OrderedOffloadingToolchains.insert(
43
30.3k
      std::make_pair(Action::OFK_Host, &DefaultToolChain));
44
30.3k
}
45
46
30.3k
Compilation::~Compilation() {
47
30.3k
  // Remove temporary files. This must be done before arguments are freed, as
48
30.3k
  // the file names might be derived from the input arguments.
49
30.3k
  if (!TheDriver.isSaveTempsEnabled() && 
!ForceKeepTempFiles30.2k
)
50
30.2k
    CleanupFileList(TempFiles);
51
30.3k
52
30.3k
  delete TranslatedArgs;
53
30.3k
  delete Args;
54
30.3k
55
30.3k
  // Free any derived arg lists.
56
30.3k
  for (auto Arg : TCArgs)
57
33.0k
    if (Arg.second != TranslatedArgs)
58
25.1k
      delete Arg.second;
59
30.3k
}
60
61
const DerivedArgList &
62
Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
63
76.0k
                                 Action::OffloadKind DeviceOffloadKind) {
64
76.0k
  if (!TC)
65
0
    TC = &DefaultToolChain;
66
76.0k
67
76.0k
  DerivedArgList *&Entry = TCArgs[{TC, BoundArch, DeviceOffloadKind}];
68
76.0k
  if (!Entry) {
69
33.0k
    SmallVector<Arg *, 4> AllocatedArgs;
70
33.0k
    DerivedArgList *OpenMPArgs = nullptr;
71
33.0k
    // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
72
33.0k
    if (DeviceOffloadKind == Action::OFK_OpenMP) {
73
91
      const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
74
91
      bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
75
91
      OpenMPArgs = TC->TranslateOpenMPTargetArgs(
76
91
          *TranslatedArgs, SameTripleAsHost, AllocatedArgs);
77
91
    }
78
33.0k
79
33.0k
    if (!OpenMPArgs) {
80
33.0k
      Entry = TC->TranslateArgs(*TranslatedArgs, BoundArch, DeviceOffloadKind);
81
33.0k
      if (!Entry)
82
7.93k
        Entry = TranslatedArgs;
83
33.0k
    } else {
84
37
      Entry = TC->TranslateArgs(*OpenMPArgs, BoundArch, DeviceOffloadKind);
85
37
      if (!Entry)
86
0
        Entry = OpenMPArgs;
87
37
      else
88
37
        delete OpenMPArgs;
89
37
    }
90
33.0k
91
33.0k
    // Add allocated arguments to the final DAL.
92
33.0k
    for (auto ArgPtr : AllocatedArgs)
93
35
      Entry->AddSynthesizedArg(ArgPtr);
94
33.0k
  }
95
76.0k
96
76.0k
  return *Entry;
97
76.0k
}
98
99
7.44k
bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
100
7.44k
  // FIXME: Why are we trying to remove files that we have not created? For
101
7.44k
  // example we should only try to remove a temporary assembly file if
102
7.44k
  // "clang -cc1" succeed in writing it. Was this a workaround for when
103
7.44k
  // clang was writing directly to a .s file and sometimes leaving it behind
104
7.44k
  // during a failure?
105
7.44k
106
7.44k
  // FIXME: If this is necessary, we can still try to split
107
7.44k
  // llvm::sys::fs::remove into a removeFile and a removeDir and avoid the
108
7.44k
  // duplicated stat from is_regular_file.
109
7.44k
110
7.44k
  // Don't try to remove files which we don't have write access to (but may be
111
7.44k
  // able to remove), or non-regular files. Underlying tools may have
112
7.44k
  // intentionally not overwritten them.
113
7.44k
  if (!llvm::sys::fs::can_write(File) || 
!llvm::sys::fs::is_regular_file(File)7.31k
)
114
147
    return true;
115
7.29k
116
7.29k
  if (std::error_code EC = llvm::sys::fs::remove(File)) {
117
0
    // Failure is only failure if the file exists and is "regular". We checked
118
0
    // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
119
0
    // so we don't need to check again.
120
0
121
0
    if (IssueErrors)
122
0
      getDriver().Diag(diag::err_drv_unable_to_remove_file)
123
0
        << EC.message();
124
0
    return false;
125
0
  }
126
7.29k
  return true;
127
7.29k
}
128
129
bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,
130
30.2k
                                  bool IssueErrors) const {
131
30.2k
  bool Success = true;
132
30.2k
  for (const auto &File: Files)
133
7.32k
    Success &= CleanupFile(File, IssueErrors);
134
30.2k
  return Success;
135
30.2k
}
136
137
bool Compilation::CleanupFileMap(const ArgStringMap &Files,
138
                                 const JobAction *JA,
139
211
                                 bool IssueErrors) const {
140
211
  bool Success = true;
141
211
  for (const auto &File : Files) {
142
146
    // If specified, only delete the files associated with the JobAction.
143
146
    // Otherwise, delete all files in the map.
144
146
    if (JA && File.first != JA)
145
34
      continue;
146
112
    Success &= CleanupFile(File.second, IssueErrors);
147
112
  }
148
211
  return Success;
149
211
}
150
151
int Compilation::ExecuteCommand(const Command &C,
152
18.1k
                                const Command *&FailingCommand) const {
153
18.1k
  if ((getDriver().CCPrintOptions ||
154
18.1k
       
getArgs().hasArg(options::OPT_v)18.1k
) &&
!getDriver().CCGenDiagnostics73
) {
155
73
    raw_ostream *OS = &llvm::errs();
156
73
    std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
157
73
158
73
    // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the
159
73
    // output stream.
160
73
    if (getDriver().CCPrintOptions && 
getDriver().CCPrintOptionsFilename1
) {
161
1
      std::error_code EC;
162
1
      OwnedStream.reset(new llvm::raw_fd_ostream(
163
1
          getDriver().CCPrintOptionsFilename, EC,
164
1
          llvm::sys::fs::F_Append | llvm::sys::fs::F_Text));
165
1
      if (EC) {
166
0
        getDriver().Diag(diag::err_drv_cc_print_options_failure)
167
0
            << EC.message();
168
0
        FailingCommand = &C;
169
0
        return 1;
170
0
      }
171
1
      OS = OwnedStream.get();
172
1
    }
173
73
174
73
    if (getDriver().CCPrintOptions)
175
1
      *OS << "[Logging clang options]";
176
73
177
73
    C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions);
178
73
  }
179
18.1k
180
18.1k
  std::string Error;
181
18.1k
  bool ExecutionFailed;
182
18.1k
  int Res = C.Execute(Redirects, &Error, &ExecutionFailed);
183
18.1k
  if (!Error.empty()) {
184
8
    assert(Res && "Error string set with 0 result code!");
185
8
    getDriver().Diag(diag::err_drv_command_failure) << Error;
186
8
  }
187
18.1k
188
18.1k
  if (Res)
189
206
    FailingCommand = &C;
190
18.1k
191
18.1k
  return ExecutionFailed ? 
11
:
Res18.1k
;
192
18.1k
}
193
194
using FailingCommandList = SmallVectorImpl<std::pair<int, const Command *>>;
195
196
static bool ActionFailed(const Action *A,
197
18.2k
                         const FailingCommandList &FailingCommands) {
198
18.2k
  if (FailingCommands.empty())
199
18.1k
    return false;
200
80
201
80
  // CUDA/HIP can have the same input source code compiled multiple times so do
202
80
  // not compiled again if there are already failures. It is OK to abort the
203
80
  // CUDA pipeline on errors.
204
80
  if (A->isOffloading(Action::OFK_Cuda) || 
A->isOffloading(Action::OFK_HIP)65
)
205
15
    return true;
206
65
207
65
  for (const auto &CI : FailingCommands)
208
69
    if (A == &(CI.second->getSource()))
209
25
      return true;
210
65
211
65
  
for (const auto *AI : A->inputs())40
212
37
    if (ActionFailed(AI, FailingCommands))
213
28
      return true;
214
40
215
40
  
return false12
;
216
40
}
217
218
static bool InputsOk(const Command &C,
219
18.1k
                     const FailingCommandList &FailingCommands) {
220
18.1k
  return !ActionFailed(&C.getSource(), FailingCommands);
221
18.1k
}
222
223
void Compilation::ExecuteJobs(const JobList &Jobs,
224
15.3k
                              FailingCommandList &FailingCommands) const {
225
15.3k
  // According to UNIX standard, driver need to continue compiling all the
226
15.3k
  // inputs on the command line even one of them failed.
227
15.3k
  // In all but CLMode, execute all the jobs unless the necessary inputs for the
228
15.3k
  // job is missing due to previous failures.
229
18.1k
  for (const auto &Job : Jobs) {
230
18.1k
    if (!InputsOk(Job, FailingCommands))
231
40
      continue;
232
18.1k
    const Command *FailingCommand = nullptr;
233
18.1k
    if (int Res = ExecuteCommand(Job, FailingCommand)) {
234
206
      FailingCommands.push_back(std::make_pair(Res, FailingCommand));
235
206
      // Bail as soon as one command fails in cl driver mode.
236
206
      if (TheDriver.IsCLMode())
237
4
        return;
238
206
    }
239
18.1k
  }
240
15.3k
}
241
242
23
void Compilation::initCompilationForDiagnostics() {
243
23
  ForDiagnostics = true;
244
23
245
23
  // Free actions and jobs.
246
23
  Actions.clear();
247
23
  AllActions.clear();
248
23
  Jobs.clear();
249
23
250
23
  // Remove temporary files.
251
23
  if (!TheDriver.isSaveTempsEnabled() && !ForceKeepTempFiles)
252
23
    CleanupFileList(TempFiles);
253
23
254
23
  // Clear temporary/results file lists.
255
23
  TempFiles.clear();
256
23
  ResultFiles.clear();
257
23
  FailureResultFiles.clear();
258
23
259
23
  // Remove any user specified output.  Claim any unclaimed arguments, so as
260
23
  // to avoid emitting warnings about unused args.
261
23
  OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
262
23
                                options::OPT_MMD };
263
92
  for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; 
++i69
) {
264
69
    if (TranslatedArgs->hasArg(OutputOpts[i]))
265
4
      TranslatedArgs->eraseArg(OutputOpts[i]);
266
69
  }
267
23
  TranslatedArgs->ClaimAllArgs();
268
23
269
23
  // Redirect stdout/stderr to /dev/null.
270
23
  Redirects = {None, {""}, {""}};
271
23
272
23
  // Temporary files added by diagnostics should be kept.
273
23
  ForceKeepTempFiles = true;
274
23
}
275
276
27.8k
StringRef Compilation::getSysRoot() const {
277
27.8k
  return getDriver().SysRoot;
278
27.8k
}
279
280
0
void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
281
0
  this->Redirects = Redirects;
282
0
}