mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 05:16:42 +00:00

This patch reworks generation for the `CFGScopeBegin`, `CFGScopeEnd`, and `CFGLiftimeEnd`, in a way that they are now compatible with each other and `CFGAutomaticObjDtor`. All of the above elements are now generated by a single code path, that conditionally inserts elements if they are requested. In addition, the handling of `goto` statements is improved. The `goto` statement may leave multiple scopes (and trigger destruction and lifetime end for the affected variables) and enter multiple scopes, for example: ```lang=C++ { int s1; { int s2; goto label; // leaves s1, s2, and enters t1 t1 } } { int t1; { int t2; label: } } ``` This is performed by first determining the shared parent scope of the source and destination. And then emitting elements for exiting each scope between the source and the parent, and entering each scope between the parent and destination. All such elements are appended to the source block, as one label may be reached from multiple scopes. Finally, the approach for handling backward jumps is changed. When connecting a source block to a destination block that requires the insertion of additional elements, we put this element into a new block, which is then linked between the source and the destination block. For example: ```lang=C++ { int t; label: // Destination block referred to as 'DB' } { // Source block referred to as 'SB' Obj s; goto label; } ``` The jump between `SB` with terminator `T: goto` and `DB` should be coupled with the following CFG elements: ``` CFGAutomaticObjDtor(s) CFGLifetimeEnd(s) CFGScopeEnd(s) CFGScopeBegin(t) ``` To handle such situations, we create a new link (`LB`) that is linked as the predecessor of `DB`, to which we transfer the terminator (`goto` statement) of `SB`. Then `LB` is handled in the same manner as the source block in the case of forward jumps. This produces CFG that looks like this: ``` SB -> LB (T: goto) -> DB ``` Finally, the resulting block is linked as the successor of `SB`. Such an approach uses existing handling of the `noreturn` destructors. As a reminder, for each destructor of an automatic object that is marked as `noreturn`, a new `noreturn` block (marked `NBn`) is created, at the destructor is inserted at the end of it. To illustrate, given two `noreturn` destructors, we will have: ``` SB -> NB1 (noreturn) NB2 (noreturn) LB (T:goto) -> DB ``` Reviewed By: ymandel, steakhal Differential Revision: https://reviews.llvm.org/D153273
21 lines
517 B
C
21 lines
517 B
C
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -verify %s
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-config cfg-scopes=true -verify %s
|
|
// expected-no-diagnostics
|
|
|
|
// This is a test case for the issue reported in PR 2819:
|
|
// http://llvm.org/bugs/show_bug.cgi?id=2819
|
|
// The flow-sensitive dataflow solver should work even when no block in
|
|
// the CFG reaches the exit block.
|
|
|
|
int g(int x);
|
|
void h(int x);
|
|
|
|
int f(int x)
|
|
{
|
|
out_err:
|
|
if (g(x)) {
|
|
h(x);
|
|
}
|
|
goto out_err;
|
|
}
|