Skip to content

Commit 18edb1f

Browse files
committed
[CAS depscan] Treat an error from driver's implicit CAS dep-scanning as if the main compilation has failed
If diagnostic errors occur during the clang driver's implicit CAS dep-scanning (like "header not found") then fail the depscan action directly. Previously CASFS dep-scanning was ignoring errors and deferring them for the main compilation but for include-tree dep-scanning we need to fail early, since the invariant for the main compilation is that all the header includes have already been resolved successfully.
1 parent bff52eb commit 18edb1f

File tree

11 files changed

+173
-57
lines changed

11 files changed

+173
-57
lines changed

clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,30 @@ class DependencyScanningTool {
100100
llvm::Expected<llvm::cas::ObjectProxy>
101101
getDependencyTree(const std::vector<std::string> &CommandLine, StringRef CWD);
102102

103+
/// If \p DiagGenerationAsCompilation is true it will generate error
104+
/// diagnostics same way as the normal compilation, with "N errors generated"
105+
/// message and the serialized diagnostics file emitted if the
106+
/// \p DiagOpts.DiagnosticSerializationFile setting is set for the invocation.
103107
llvm::Expected<llvm::cas::ObjectProxy>
104108
getDependencyTreeFromCompilerInvocation(
105109
std::shared_ptr<CompilerInvocation> Invocation, StringRef CWD,
106-
DiagnosticConsumer &DiagsConsumer,
110+
DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS,
111+
bool DiagGenerationAsCompilation,
107112
llvm::function_ref<StringRef(const llvm::vfs::CachedDirectoryEntry &)>
108113
RemapPath = nullptr);
109114

110115
Expected<cas::IncludeTreeRoot>
111116
getIncludeTree(cas::CASDB &DB, const std::vector<std::string> &CommandLine,
112117
StringRef CWD);
113118

119+
/// If \p DiagGenerationAsCompilation is true it will generate error
120+
/// diagnostics same way as the normal compilation, with "N errors generated"
121+
/// message and the serialized diagnostics file emitted if the
122+
/// \p DiagOpts.DiagnosticSerializationFile setting is set for the invocation.
114123
Expected<cas::IncludeTreeRoot> getIncludeTreeFromCompilerInvocation(
115124
cas::CASDB &DB, std::shared_ptr<CompilerInvocation> Invocation,
116-
StringRef CWD, DiagnosticConsumer &DiagsConsumer);
125+
StringRef CWD, DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS,
126+
bool DiagGenerationAsCompilation);
117127

118128
/// Collect the full module dependency graph for the input, ignoring any
119129
/// modules which have already been seen. If \p ModuleName isn't empty, this

clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,15 @@ class DependencyScanningWorker {
8686
ScanningOutputFormat getFormat() const { return Format; }
8787

8888
/// Scan from a compiler invocation.
89+
/// If \p DiagGenerationAsCompilation is true it will generate error
90+
/// diagnostics same way as the normal compilation, with "N errors generated"
91+
/// message and the serialized diagnostics file emitted if the
92+
/// \p DiagOpts.DiagnosticSerializationFile setting is set for the invocation.
8993
void computeDependenciesFromCompilerInvocation(
9094
std::shared_ptr<CompilerInvocation> Invocation,
9195
StringRef WorkingDirectory, DependencyScanningConsumerBase &Consumer,
92-
DiagnosticConsumer &DiagsConsumer);
96+
DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS,
97+
bool DiagGenerationAsCompilation);
9398

9499
ScanningOutputFormat getScanningFormat() const { return Format; }
95100

clang/include/clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct DepscanPrefixMapping {
4141

4242
Expected<llvm::cas::CASID> scanAndUpdateCC1InlineWithTool(
4343
tooling::dependencies::DependencyScanningTool &Tool,
44-
DiagnosticConsumer &DiagsConsumer, const char *Exec,
44+
DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS, const char *Exec,
4545
CompilerInvocation &Invocation, StringRef WorkingDirectory,
4646
const cc1depscand::DepscanPrefixMapping &PrefixMapping);
4747

clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,17 @@ DependencyScanningTool::getDependencyTree(
191191
llvm::Expected<llvm::cas::ObjectProxy>
192192
DependencyScanningTool::getDependencyTreeFromCompilerInvocation(
193193
std::shared_ptr<CompilerInvocation> Invocation, StringRef CWD,
194-
DiagnosticConsumer &DiagsConsumer,
194+
DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS,
195+
bool DiagGenerationAsCompilation,
195196
llvm::function_ref<StringRef(const llvm::vfs::CachedDirectoryEntry &)>
196197
RemapPath) {
197198
llvm::cas::CachingOnDiskFileSystem &FS = Worker.getCASFS();
198199
FS.trackNewAccesses();
199200
FS.setCurrentWorkingDirectory(CWD);
200201
MakeDependencyTree DepsConsumer(FS);
201-
Worker.computeDependenciesFromCompilerInvocation(std::move(Invocation), CWD,
202-
DepsConsumer, DiagsConsumer);
202+
Worker.computeDependenciesFromCompilerInvocation(
203+
std::move(Invocation), CWD, DepsConsumer, DiagsConsumer, VerboseOS,
204+
DiagGenerationAsCompilation);
203205
// return DepsConsumer.makeTree();
204206
//
205207
// FIXME: See FIXME in getDepencyTree().
@@ -380,10 +382,12 @@ Expected<cas::IncludeTreeRoot> DependencyScanningTool::getIncludeTree(
380382
Expected<cas::IncludeTreeRoot>
381383
DependencyScanningTool::getIncludeTreeFromCompilerInvocation(
382384
cas::CASDB &DB, std::shared_ptr<CompilerInvocation> Invocation,
383-
StringRef CWD, DiagnosticConsumer &DiagsConsumer) {
385+
StringRef CWD, DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS,
386+
bool DiagGenerationAsCompilation) {
384387
IncludeTreePPConsumer Consumer(DB);
385-
Worker.computeDependenciesFromCompilerInvocation(std::move(Invocation), CWD,
386-
Consumer, DiagsConsumer);
388+
Worker.computeDependenciesFromCompilerInvocation(
389+
std::move(Invocation), CWD, Consumer, DiagsConsumer, VerboseOS,
390+
DiagGenerationAsCompilation);
387391
return Consumer.getIncludeTree();
388392
}
389393

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,16 @@ class DependencyScanningAction : public tooling::ToolAction {
198198
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
199199
llvm::IntrusiveRefCntPtr<DependencyScanningCASFilesystem> DepCASFS,
200200
ScanningOutputFormat Format, bool OptimizeArgs, bool EmitDependencyFile,
201-
bool DisableFree, llvm::Optional<StringRef> ModuleName = None)
201+
bool DiagGenerationAsCompilation, bool DisableFree,
202+
llvm::Optional<StringRef> ModuleName = None,
203+
raw_ostream *VerboseOS = nullptr)
202204
: WorkingDirectory(WorkingDirectory), Consumer(Consumer),
203205
CASOpts(CASOpts), DepFS(std::move(DepFS)),
204206
DepCASFS(std::move(DepCASFS)), Format(Format),
205207
OptimizeArgs(OptimizeArgs), EmitDependencyFile(EmitDependencyFile),
206-
DisableFree(DisableFree), ModuleName(ModuleName) {}
208+
DiagGenerationAsCompilation(DiagGenerationAsCompilation),
209+
DisableFree(DisableFree), ModuleName(ModuleName), VerboseOS(VerboseOS) {
210+
}
207211

208212
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
209213
FileManager *FileMgr,
@@ -220,10 +224,13 @@ class DependencyScanningAction : public tooling::ToolAction {
220224
ScanInstance.getInvocation().getCASOpts() = CASOpts;
221225

222226
// Create the compiler's actual diagnostics engine.
223-
sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
227+
if (!DiagGenerationAsCompilation)
228+
sanitizeDiagOpts(ScanInstance.getDiagnosticOpts());
224229
ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
225230
if (!ScanInstance.hasDiagnostics())
226231
return false;
232+
if (VerboseOS)
233+
ScanInstance.setVerboseOutputStream(*VerboseOS);
227234

228235
ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath =
229236
true;
@@ -363,8 +370,10 @@ class DependencyScanningAction : public tooling::ToolAction {
363370
ScanningOutputFormat Format;
364371
bool OptimizeArgs;
365372
bool EmitDependencyFile = false;
373+
bool DiagGenerationAsCompilation;
366374
bool DisableFree;
367375
llvm::Optional<StringRef> ModuleName;
376+
raw_ostream *VerboseOS;
368377
};
369378

370379
} // end anonymous namespace
@@ -464,9 +473,10 @@ llvm::Error DependencyScanningWorker::computeDependencies(
464473
bool DisableFree = true;
465474
DependencyScanningAction Action(
466475
WorkingDirectory, Consumer, getCASOpts(), DepFS,
467-
DepCASFS, Format,
468-
OptimizeArgs, /*EmitDependencyFile=*/false,
469-
DisableFree, ModuleName);
476+
DepCASFS, Format, OptimizeArgs,
477+
/*EmitDependencyFile=*/false,
478+
/*DiagGenerationAsCompilation=*/false, DisableFree,
479+
ModuleName);
470480
// Create an invocation that uses the underlying file
471481
// system to ensure that any file system requests that
472482
// are made by the driver do not go through the
@@ -483,7 +493,8 @@ llvm::Error DependencyScanningWorker::computeDependencies(
483493
void DependencyScanningWorker::computeDependenciesFromCompilerInvocation(
484494
std::shared_ptr<CompilerInvocation> Invocation, StringRef WorkingDirectory,
485495
DependencyScanningConsumerBase &DepsConsumer,
486-
DiagnosticConsumer &DiagsConsumer) {
496+
DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS,
497+
bool DiagGenerationAsCompilation) {
487498
RealFS->setCurrentWorkingDirectory(WorkingDirectory);
488499

489500
// Adjust the invocation.
@@ -499,7 +510,7 @@ void DependencyScanningWorker::computeDependenciesFromCompilerInvocation(
499510

500511
// Make the output file path absolute relative to WorkingDirectory.
501512
std::string &DepFile = Invocation->getDependencyOutputOpts().OutputFile;
502-
if (!llvm::sys::path::is_absolute(DepFile)) {
513+
if (!DepFile.empty() && !llvm::sys::path::is_absolute(DepFile)) {
503514
// FIXME: On Windows, WorkingDirectory is insufficient for making an
504515
// absolute path if OutputFile has a root name.
505516
llvm::SmallString<128> Path = StringRef(DepFile);
@@ -509,11 +520,11 @@ void DependencyScanningWorker::computeDependenciesFromCompilerInvocation(
509520

510521
// FIXME: EmitDependencyFile should only be set when it's for a real
511522
// compilation.
512-
DependencyScanningAction Action(WorkingDirectory, DepsConsumer, getCASOpts(),
513-
DepFS, DepCASFS, Format,
514-
/*OptimizeArgs=*/false,
515-
/*EmitDependencyFile=*/true,
516-
/*DisableFree=*/false);
523+
DependencyScanningAction Action(
524+
WorkingDirectory, DepsConsumer, getCASOpts(), DepFS, DepCASFS, Format,
525+
/*OptimizeArgs=*/false,
526+
/*EmitDependencyFile=*/!DepFile.empty(), DiagGenerationAsCompilation,
527+
/*DisableFree=*/false, /*ModuleName=*/None, VerboseOS);
517528

518529
// Ignore result; we're just collecting dependencies.
519530
//

clang/lib/Tooling/DependencyScanning/ScanAndUpdateArgs.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ static void updateCompilerInvocation(CompilerInvocation &Invocation,
181181

182182
Expected<llvm::cas::CASID> clang::scanAndUpdateCC1InlineWithTool(
183183
tooling::dependencies::DependencyScanningTool &Tool,
184-
DiagnosticConsumer &DiagsConsumer, const char *Exec,
184+
DiagnosticConsumer &DiagsConsumer, raw_ostream *VerboseOS, const char *Exec,
185185
CompilerInvocation &Invocation, StringRef WorkingDirectory,
186186
const cc1depscand::DepscanPrefixMapping &PrefixMapping) {
187187
llvm::cas::CachingOnDiskFileSystem &FS = Tool.getCachingFileSystem();
@@ -197,10 +197,16 @@ Expected<llvm::cas::CASID> clang::scanAndUpdateCC1InlineWithTool(
197197
computeFullMapping(Saver, Exec, Invocation, PrefixMapping, Mapper))
198198
return std::move(E);
199199

200+
auto ScanInvocation = std::make_shared<CompilerInvocation>(Invocation);
201+
// An error during dep-scanning is treated as if the main compilation has
202+
// failed, but warnings are ignored and deferred for the main compilation.
203+
ScanInvocation->getDiagnosticOpts().IgnoreWarnings = true;
204+
200205
Optional<llvm::cas::CASID> Root;
201206
if (Error E = Tool.getDependencyTreeFromCompilerInvocation(
202-
std::make_shared<CompilerInvocation>(Invocation),
203-
WorkingDirectory, DiagsConsumer,
207+
std::move(ScanInvocation),
208+
WorkingDirectory, DiagsConsumer, VerboseOS,
209+
/*DiagGenerationAsCompilation*/ true,
204210
[&](const llvm::vfs::CachedDirectoryEntry &Entry) {
205211
return Mapper.map(Entry);
206212
})

clang/test/CAS/depscan-with-error.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// REQUIRES: ansi-escape-sequences
2+
3+
// RUN: rm -rf %t && mkdir -p %t
4+
5+
// RUN: not %clang -cc1depscan -fdepscan=inline -cc1-args -cc1 -triple x86_64-apple-macos11 -x c %s -o %t/t.o -fcas-path %t/cas \
6+
// RUN: 2>&1 | FileCheck %s -check-prefix=ERROR
7+
8+
// Using normal compilation as baseline.
9+
// RUN: not %clang -target x86_64-apple-macos11 -c %s -o %t.o -fmodules-cache-path=%t/mcp --serialize-diagnostics %t/t1.diag \
10+
// RUN: 2>&1 | FileCheck %s -check-prefix=ERROR -check-prefix=DRIVER
11+
// RUN: not env LLVM_CACHE_CAS_PATH=%t/cas %clang-cache \
12+
// RUN: %clang -target x86_64-apple-macos11 -c %s -o %t.o -fmodules-cache-path=%t/mcp --serialize-diagnostics %t/t2.diag \
13+
// RUN: 2>&1 | FileCheck %s -check-prefix=ERROR -check-prefix=DRIVER
14+
// RUN: not env LLVM_CACHE_CAS_PATH=%t/cas cache-build-session %clang-cache \
15+
// RUN: %clang -target x86_64-apple-macos11 -c %s -o %t.o -fmodules-cache-path=%t/mcp --serialize-diagnostics %t/t3.diag \
16+
// RUN: 2>&1 | FileCheck %s -check-prefix=ERROR -check-prefix=DRIVER
17+
18+
// RUN: diff %t/t1.diag %t/t2.diag
19+
// RUN: diff %t/t1.diag %t/t3.diag
20+
21+
// DRIVER: warning: argument unused during compilation
22+
// ERROR: error: 'non-existent.h' file not found
23+
// ERROR: 1 error generated.
24+
25+
// Make sure successful compilation clears the diagnostic file.
26+
// RUN: echo "int x;" > %t/a.c
27+
// RUN: echo "int y;" > %t/b.c
28+
// RUN: env LLVM_CACHE_CAS_PATH=%t/cas %clang-cache \
29+
// RUN: %clang -target x86_64-apple-macos11 -c %t/a.c -o %t.o --serialize-diagnostics %t/t2.diag
30+
// RUN: env LLVM_CACHE_CAS_PATH=%t/cas cache-build-session %clang-cache \
31+
// RUN: %clang -target x86_64-apple-macos11 -c %t/b.c -o %t.o --serialize-diagnostics %t/t3.diag
32+
33+
// RUN: c-index-test -read-diagnostics %t/t2.diag 2>&1 | FileCheck %s -check-prefix=SERIAL
34+
// RUN: c-index-test -read-diagnostics %t/t3.diag 2>&1 | FileCheck %s -check-prefix=SERIAL
35+
// SERIAL: Number of diagnostics: 0
36+
37+
// Make sure warnings are still emitted for normal compilation.
38+
// RUN: echo "#warning some warning" > %t/warn.c
39+
// RUN: env LLVM_CACHE_CAS_PATH=%t/cas %clang-cache \
40+
// RUN: %clang -target x86_64-apple-macos11 -c %t/warn.c -o %t.o \
41+
// RUN: 2>&1 | FileCheck %s -check-prefix=WARN
42+
// WARN: warning: some warning
43+
44+
// Make sure diagnostics emitted during CAS dep-scanning respect the color settings.
45+
// RUN: not %clang -target x86_64-apple-macos11 -c %s -o %t.o -fdiagnostics-color=always -fansi-escape-codes \
46+
// RUN: 2>&1 | FileCheck %s -check-prefix=COLOR-DIAG
47+
// RUN: not env LLVM_CACHE_CAS_PATH=%t/cas %clang-cache \
48+
// RUN: %clang -target x86_64-apple-macos11 -c %s -o %t.o -fdiagnostics-color=always -fansi-escape-codes \
49+
// RUN: 2>&1 | FileCheck %s -check-prefix=COLOR-DIAG
50+
// RUN: not env LLVM_CACHE_CAS_PATH=%t/cas cache-build-session %clang-cache \
51+
// RUN: %clang -target x86_64-apple-macos11 -c %s -o %t.o -fdiagnostics-color=always -fansi-escape-codes \
52+
// RUN: 2>&1 | FileCheck %s -check-prefix=COLOR-DIAG
53+
// COLOR-DIAG: [[RED:.\[0;1;31m]]fatal error: [[RESET:.\[0m]]
54+
55+
#include "non-existent.h"

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,9 @@ static bool emitCompilationDBWithCASTreeArguments(
340340
FileManager *Files,
341341
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
342342
DiagnosticConsumer *DiagConsumer) override {
343-
Expected<llvm::cas::CASID> Root =
344-
scanAndUpdateCC1InlineWithTool(WorkerTool, DiagsConsumer, Exec,
345-
*Invocation, CWD, PrefixMapping);
343+
Expected<llvm::cas::CASID> Root = scanAndUpdateCC1InlineWithTool(
344+
WorkerTool, DiagsConsumer, /*VerboseOS*/ nullptr, Exec,
345+
*Invocation, CWD, PrefixMapping);
346346
if (!Root) {
347347
llvm::consumeError(Root.takeError());
348348
return false;

clang/tools/driver/cc1depscanProtocol.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ CC1DepScanDProtocol::getDepscanPrefixMapping(llvm::StringSaver &Saver,
364364
llvm::Error
365365
CC1DepScanDProtocol::getScanResult(llvm::StringSaver &Saver, ResultKind &Result,
366366
StringRef &FailedReason, StringRef &RootID,
367-
SmallVectorImpl<const char *> &Args) {
367+
SmallVectorImpl<const char *> &Args,
368+
StringRef &DiagnosticOutput) {
368369
if (Error E = getResultKind(Result))
369370
return E;
370371

@@ -378,17 +379,20 @@ CC1DepScanDProtocol::getScanResult(llvm::StringSaver &Saver, ResultKind &Result,
378379

379380
if (Error E = getString(Saver, RootID))
380381
return E;
381-
return getArgs(Saver, Args);
382+
if (Error E = getArgs(Saver, Args))
383+
return E;
384+
return getString(Saver, DiagnosticOutput);
382385
}
383386

384-
llvm::Error
385-
CC1DepScanDProtocol::putScanResultSuccess(StringRef RootID,
386-
ArrayRef<const char *> Args) {
387+
llvm::Error CC1DepScanDProtocol::putScanResultSuccess(
388+
StringRef RootID, ArrayRef<const char *> Args, StringRef DiagnosticOutput) {
387389
if (Error E = putResultKind(SuccessResult))
388390
return E;
389391
if (Error E = putString(RootID))
390392
return E;
391-
return putArgs(Args);
393+
if (Error E = putArgs(Args))
394+
return E;
395+
return putString(DiagnosticOutput);
392396
}
393397

394398
llvm::Error CC1DepScanDProtocol::putScanResultFailed(StringRef Reason) {

clang/tools/driver/cc1depscanProtocol.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,12 @@ class CC1DepScanDProtocol {
152152

153153
llvm::Error putScanResultFailed(StringRef Reason);
154154
llvm::Error putScanResultSuccess(StringRef RootID,
155-
ArrayRef<const char *> Args);
155+
ArrayRef<const char *> Args,
156+
StringRef DiagnosticOutput);
156157
llvm::Error getScanResult(llvm::StringSaver &Saver, ResultKind &Result,
157158
StringRef &FailedReason, StringRef &RootID,
158-
SmallVectorImpl<const char *> &Args);
159+
SmallVectorImpl<const char *> &Args,
160+
StringRef &DiagnosticOutput);
159161

160162
explicit CC1DepScanDProtocol(int Socket) : Socket(Socket) {}
161163
CC1DepScanDProtocol() = delete;

0 commit comments

Comments
 (0)