[clang] Fix serialized diagnostics edge-cases

The Clang frontend sometimes fails on the following assertion when launched with `-serialize-diagnostic-file <x>`:

```
Assertion failed: (BlockScope.empty() && CurAbbrevs.empty() && "Block imbalance"), function ~BitstreamWriter, file BitstreamWriter.h, line 125.
```

This was first noticed when passing an unknown command-line argument to `-cc1`.

It turns out the `DiagnosticConsumer::finish()` function should be called as soon as processing of all source files ends, but there are some code paths where that doesn't happen:

1. when command line parsing fails in `cc1_main()`,
2. when `!Act.PrepareToExecute(*this)` or `!createTarget()` evaluate to `true` in `CompilerInstance::ExecuteAction` and the function returns early.

This patch ensures `finish()` is called in all those code paths.

Reviewed By: Bigcheese

Differential Revision: https://reviews.llvm.org/D118150
This commit is contained in:
Jan Svoboda 2022-01-26 11:21:49 +01:00
parent 600c6714ac
commit 76cb4cd074
5 changed files with 21 additions and 4 deletions

View File

@ -37,6 +37,7 @@
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/InMemoryModuleCache.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CrashRecoveryContext.h"
@ -996,6 +997,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// DesiredStackSpace available.
noteBottomOfStack();
auto FinishDiagnosticClient = llvm::make_scope_exit([&]() {
// Notify the diagnostic client that all files were processed.
getDiagnosticClient().finish();
});
raw_ostream &OS = getVerboseOutputStream();
if (!Act.PrepareToExecute(*this))
@ -1034,9 +1040,6 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}
// Notify the diagnostic client that all files were processed.
getDiagnostics().getClient()->finish();
if (getDiagnosticOpts().ShowCarets) {
// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.

View File

@ -0,0 +1,4 @@
// RUN: rm -rf %t && mkdir %t
// RUN: not %clang_cc1 -emit-header-module %s -o %t/out.pcm -serialize-diagnostic-file %t/diag 2>&1 | FileCheck %s
// CHECK: error: header module compilation requires '-fmodules', '-std=c++20', or '-fmodules-ts'

View File

@ -0,0 +1,4 @@
// RUN: rm -rf %t && mkdir %t
// RUN: not %clang_cc1 %s -unknown-argument -serialize-diagnostic-file %t/diag -o /dev/null 2>&1 | FileCheck %s
// CHECK: error: unknown argument: '-unknown-argument'

View File

@ -0,0 +1,4 @@
// RUN: rm -rf %t && mkdir %t
// RUN: not %clang_cc1 %s -triple blah-unknown-unknown -serialize-diagnostic-file %t/diag -o /dev/null 2>&1 | FileCheck %s
// CHECK: error: unknown target triple 'blah-unknown-unknown', please use -triple or -arch

View File

@ -237,8 +237,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
static_cast<void*>(&Clang->getDiagnostics()));
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
if (!Success)
if (!Success) {
Clang->getDiagnosticClient().finish();
return 1;
}
// Execute the frontend actions.
{