llvm / llvm/llvm-project

[clang-tidy]: `bugprone-unchecked-optional-access` false-positive if inside a loop we use checked optional value (might be a regression of Dataflow Analysis)

Open
#174,250 11 comments 0 reactions 0 assignees View on GitHub
clang-tidy clang:dataflow false-positive
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Way to reproduce

Smallest example which me and my colleague managed to make:
```cpp
#include
#include

std::vector> getOptionals();

void test() {

for (const auto &opt : getOptionals()) {
if (opt.has_value()) {
int x = opt.value(); // NO ERROR
}
}

std::optional opt;
if (opt.has_value()) {
for (int i = 0; i < 10; ++i) {
int x = opt.value(); // NO ERROR
}
}

for (const auto &opt : getOptionals()) {
if (opt.has_value()) {
for (int i = 0; i < 10; ++i) {
int x = opt.value(); // ERROR
}
}
}

// Also happens when the loop is unbounded
for (const auto &opt : getOptionals()) {
if (opt.has_value()) {
for (;;) {
int x = opt.value(); // ERROR
}
}
}
}
```

[Compiler Explorer Link](https://compiler-explorer.com/z/9e6zjor5T)

## Initial problem / User Impact

After fixing https://github.com/llvm/llvm-project/pull/168863 I found new false-positive like:
```cpp
bsl::vector> getOptionals();

void test_with_ball_log_and_loop() {
BALL_LOG_SET_CATEGORY(__func__);

for (const auto& opt : getOptionals()) {
if (opt.has_value()) {
BALL_LOG_INFO << opt.value(); // ERROR?!
}
}
}
```

`BALL_LOG` is BDE tooling used for logging. [Link](https://bloomberg.github.io/bde-resources/doxygen/bde_api_prod/group__ball__log.html)

After some experiments, I found out that I can reproduce the same issue with `std::optional` so it was somehow connected with `BALL_LOG`.

[Compiler Explorer Link](https://compiler-explorer.com/z/vdTvqrdv1).

Removing/expanding macros and includes resulted in example from the beginning :)

---

**So even though the initial example might be niche, the original issue is a pretty common pattern.**

JFYI, I cannot reproduce it with clang-18 and clang-19 releases but I can reproduce it with clang-20 and clang-21. So maybe it's a regression??

Contributor guide

Open the contributing guide

Research direction

Start with the clang-tidy `bugprone-unchecked-optional-access` check and reproduce the issue using the examples and Compiler Explorer links in the report. Trace how checked optional values are modeled across nested and unbounded loops, then add regression coverage showing that `opt.value()` after `has_value()` is not diagnosed while existing unchecked-access diagnostics remain.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.