llvm / llvm/llvm-project

[clang-tidy] misc-include-cleaner reports <variant> unused for std::get when the variant type comes from an alias in another header

Open
#213,818 2 comments 0 reactions 0 assignees View on GitHub
clang-include-cleaner
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

`misc-include-cleaner` reports `` as unused in a file that calls `std::get` on a
`std::variant`, when the variant type reaches the file through an alias declared in another
header. `std::get`'s variant overloads are declared in ``, so the file does use a
declaration from it.

Unlike a plain unused-include false positive this one does not break the build: the alias
header pulls `` in transitively, so removing it still compiles. That is precisely
the transitive-dependency case the check exists to flag, so the suggestion quietly moves the
file in the wrong direction.

The missing-includes half does not ask for a `std::get` provider either, even with both
`` and `` removed, which suggests the call is not attributed to any header
rather than being attributed to the wrong one.

### Version

```
$ clang-tidy --version
LLVM (http://llvm.org/):
LLVM version 22.1.8
Optimized build.
```

Installed from PyPI (`clang-tidy==22.1.8`). Reproduced on macOS with libc++.

### Reproducer

`cfg.h`:

```c++
#pragma once
#include
#include
#include
namespace cfg {
using ConfigValue = std::variant;
using ConfigMap = std::map;
}
```

`g6.cc`:

```c++
#include

#include "cfg.h"

double f(const cfg::ConfigMap &m) {
return std::get(m.at("k"));
}
```

`.clang-tidy`:

```yaml
Checks: '-*,misc-include-cleaner'
CheckOptions:
- key: misc-include-cleaner.MissingIncludes
value: 'false'
```

A compilation database is required; `--` on the command line is not sufficient.

```
$ clang-tidy -p . --quiet g6.cc
g6.cc:1:1: warning: included header variant is not used directly [misc-include-cleaner]
```

### Expected

No diagnostic. `std::get(std::variant<...>&)` is declared in ``.

### Notes on the trigger

The alias-in-another-header part matters. If the variant type is spelled in the same file,
the check is correct and reports nothing:

```c++
#include

using V = std::variant;

double f(const V &v) { return std::get(v); } // no diagnostic, correct
```

Only when `std::variant` itself is never named in the file — the type arriving as
`cfg::ConfigValue` — does `` get reported, even though `std::get` is named directly
and its relevant overloads live there.

### Possibly related

#94459 was a symbol-to-header mapping problem in the same family: `` was reported
unused for `std::ranges::upper_bound` while an internal header was suggested instead.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the diagnostic with cfg.h, g6.cc, the .clang-tidy configuration, and a compilation database using clang-tidy -p . --quiet g6.cc. Trace misc-include-cleaner’s attribution of std::get when the std::variant type arrives through cfg::ConfigValue, comparing it with the direct-alias example. Done means the reproducer emits no unused diagnostic while the check still handles genuine transitive dependencies.

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
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.