Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the diagnostic verifier, plus a few other fixes. #598

Merged
merged 7 commits into from
Jun 14, 2021
52 changes: 52 additions & 0 deletions clang/docs/checkedc/3C/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,58 @@ in subdirectories, so `*.c` will not pick up all of them; instead you
can use `llvm-lit -vv .` to specify all test files under the current
directory.

### Diagnostic verification

3C supports the standard Clang diagnostic verifier
([`VerifyDiagnosticConsumer`](https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details))
for testing errors and warnings reported by 3C via its main `DiagnosticsEngine`.
(Some 3C errors and warnings are reported via other means and cannot be tested
this way; the best solution we have for them right now is to `grep` the stderr
of 3C.) Diagnostic verification can be enabled via the usual `-Xclang -verify`
compiler option; other diagnostic verification options (`-Xclang
-verify=PREFIX`, etc.) should also work as normal. These must be passed as
_compiler_ options, not `3c` options; for example, if you are using `--` on the
`3c` command line, these options must be passed _after_ the `--`.

Some notes about diagnostic verification in the context of 3C:

* Parsing of the source files uses some of the compiler logic and thus may
generate compiler warnings, just as if you ran `clang` on the code. These are
sent to the diagnostic verifier along with diagnostics generated by 3C's
analysis. If you find it distracting to have to include the compiler warnings
in the set of expected diagnostics for a test, you can turn them off via the
`-Wno-everything` compiler option (which does not affect diagnostics generated
by 3C's analysis).

* The `3c` tool works in several passes, where each pass runs on all translation
units: first `3c` parses the source files, then it runs several passes of
analysis. If a pass encounters at least one error, `3c` exits at the end of
that pass. Diagnostic verification does not change the _point_ at which `3c`
exits, but it changes the exit _code_ to indicate the result of verification
rather than the presence of errors. The verification includes the diagnostics
from all passes up to the point at which `3c` exits (i.e., the same
diagnostics that would be displayed if verification were not used). However,
an error that doesn't go via the main `DiagnosticsEngine` will cause an
unsuccessful exit code regardless of diagnostic verification. (This is
typically the behavior you want for a test.)

* Diagnostic verification is independent for each translation unit, so in tests
with multiple translation units, you'll have to be careful that preprocessing
of each translation unit sees the correct set of `expected-*` directives for
the diagnostics generated for that translation unit (or an
`expected-no-diagnostics` directive if that translation unit generates no
diagnostics, even if other translation units do generate diagnostics). Be
warned that since which translation unit generated a given diagnostic isn't
visible to a normal user, we don't put much work into coming up with sensible
rules for this, but it should at least be deterministic for testing.

Note that some 3C tests use diagnostic verification on calls to `clang` rather
than `3c`, so if you see `expected-*` directives in a test, you can look at the
`RUN` commands to see which command has `-Xclang -verify` and is using the
directives. If you want to verify diagnostics of more than one `RUN` command in
the same test, you can use different directive prefixes (`-Xclang
-verify=PREFIX`).

## Coding guidelines

Please follow [LLVM coding
Expand Down
26 changes: 19 additions & 7 deletions clang/include/clang/3C/3C.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct _3COptions {

bool AddCheckedRegions;

bool DisableCCTypeChecker;
bool EnableCCTypeChecker;

bool WarnRootCause;

Expand All @@ -68,11 +68,6 @@ struct _3COptions {
bool ForceItypes;
#endif

// Currently applies only to the rewriting phase (because it is the only phase
// that generates diagnostics, except for the declaration merging diagnostics
// that are currently fatal) and uses the default "expected" prefix.
bool VerifyDiagnosticOutput;

bool DumpUnwritableChanges;
bool AllowUnwritableChanges;

Expand Down Expand Up @@ -104,6 +99,8 @@ class _3CInterface {
const std::vector<std::string> &SourceFileList,
clang::tooling::CompilationDatabase *CompDB);

~_3CInterface();

// Call clang to provide the data
bool parseASTs();

Expand Down Expand Up @@ -141,10 +138,25 @@ class _3CInterface {
// Dump all stats related to performance.
bool dumpStats();

// Determine the exit code that the `3c` tool should exit with after the last
// 3C stage, considering diagnostic verification. Must be called exactly once
// before the _3CInterface is destructed (unless construction failed).
int determineExitCode();

private:
_3CInterface(const struct _3COptions &CCopt,
const std::vector<std::string> &SourceFileList,
clang::tooling::CompilationDatabase *CompDB, bool &Failed);
clang::tooling::CompilationDatabase *CompDB);

bool ConstructionFailed = false;
bool DeterminedExitCode = false;

bool HadNonDiagnosticError = false;

// Determine whether 3C can continue to the next stage of processing. Checks
// HadNonDiagnosticError and error diagnostics but ignores diagnostic
// verification.
bool isSuccessfulSoFar();

// saved ASTs
std::vector< std::unique_ptr< ASTUnit >> ASTs;
Expand Down
Loading