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