[clang] [NFC][analyzer] Improve tracking of the current Block & LocCtx (PR #185107)

Donát Nagy via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 9 05:30:42 PDT 2026


NagyDonat wrote:

>     * When we start to process a new block or enter a new function, we really are forced to create these locals and pass them along. With the proposed design, it is possible to forget to do that and just automatically use the field that is not up to date.

Instead of walking along a single continuous execution path, the analyzer "jumps around": each call of `dispatchWorkItem` "jumps to" another part of the graph which is often unrelated to the previously analyzed one. Within a single call to `dispatchWorkItem` the current block and location context is _almost constant_: some work items (e.g. a `BlockEdge`) change them, but these changes are immediately visible and easy to follow (AFAIK there are no repeated surprise changes).

Based on this I think the natural setup for managing the "current" block and location context is:
- At the beginning of `dispatchWorkItem` they are reset to `nullptr` (this guarantees that the stale values from the previous work item are not used).
- After this, `dispatchWorkItem` enters a big `switch` calls the `Handle` method  (`HandleBlockEdge` etc.) corresponding to the work item kind.
- These `Handle` methods determine the "new" current block and location context as soon as they can (near the beginning of the method). This block/context will remain valid until the completion of the active work item.
  - Note that these `Handle` methods form a "closed" system: it is extremely unlikely that a new one will be introduced in the future.

You say that "we really are forced to create these locals" but nothing guarantees that these local `NodeBuilderContext`s are created _correctly_, and in fact I noticed some ugly inconsistencies where e.g. the location of the `NodeBuilderContext` is wrong in `PreCall` callbacks.

By the way we often **don't "pass them along"** – the `NodeBuilderCtxt` is usually accessed through the member `currBldrCtxt` of `ExprEngine`. There are situations – e.g. [the early return in ProcessBranch](https://github.com/llvm/llvm-project/blob/6aa7538a39975fb4b12edb32d058a631646ff053/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp#L2849) where `currBldrCtxt` continues to refer to a local after the end of its lifetime.

>     * The current block and the location context are not always meaningful. What is the current block when we are processing an edge?

When processing a block edge, the "current block" is the destination block of the edge, according to code at the beginning of [`CoreEngine::HandleBlockEdge`](https://github.com/llvm/llvm-project/blob/6aa7538a39975fb4b12edb32d058a631646ff053/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp#L262). (Everything in `HandleBlockEdge` uses this `NodeBuilderContext`.)

> Or what is the current block when we are doing some AST-based (not path sensitive) checks?

Naturally, there is no current block, `CurrBlock` (and `CurrLocationContext`) should be `nullptr`.

https://github.com/llvm/llvm-project/pull/185107


More information about the cfe-commits mailing list