llvm / llvm/llvm-project

[clang-tidy] `clang-analyzer-optin.core.EnumCastOutOfRange` warns about inline functions in system headers

Open
#179,094 5 comments 0 reactions 0 assignees View on GitHub
clang:static analyzer
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

clang-tidy shouldn't warn about system headers without `--system-headers`, but I had multiple instances of `clang-analyzer-optin.core.EnumCastOutOfRange` warning about inline functions in system headers.

I don't know how I can demonstrate this in godbolt, so I'm just going to give examples on where this happens.

- Using `operator|` on [`Gtk::TreeModel::Flags`](https://gnome.pages.gitlab.gnome.org/gtkmm/group__gtkmmEnums.html#ga7a86e009cc39c176e1966fa00a74d861) from gtkmm 4.20. Runing clang-tidy 21.1.8.

I've checked the compiler command that it specifies `-isystem /usr/include/gtkmm-4.0`.

Example code:
```c++
Gtk::TreeModel::Flags::ITERS_PERSIST | Gtk::TreeModel::Flags::LIST_ONLY;
```

Example clang-tidy output:
```
/usr/include/gtkmm-4.0/gtkmm/treemodel.h:761:12: warning: The value '3' provided to the cast expression is not in the valid range of values for 'Flags' [clang-analyzer-optin.core.EnumCastOutOfRange]
761 | { return static_cast(static_cast(lhs) | static_cast(rhs)); }
| ^
/usr/include/gtkmm-4.0/gtkmm/treemodel.h:219:14: note: enum declared here
219 | enum class Flags
| ~~~~~~~~~~~^~~~~
220 | {
| ~
221 | ITERS_PERSIST = 1 << 0,
| ~~~~~~~~~~~~~~~~~~~~~~~
222 | LIST_ONLY = 1 << 1
| ~~~~~~~~~~~~~~~~~~
223 | };
| ~
/transmission/gtk/ListModelAdapter.cc:64:12: note: Calling 'operator|'
64 | return TR_GTK_TREE_MODEL_FLAGS(ITERS_PERSIST) | TR_GTK_TREE_MODEL_FLAGS(LIST_ONLY);
| ^
/transmission/gtk/GtkCompat.h:76:49: note: expanded from macro 'TR_GTK_TREE_MODEL_FLAGS'
76 | #define TR_GTK_TREE_MODEL_FLAGS(Code) IF_GTKMM4(Gtk::TreeModel::Flags::Code, Gtk::TREE_MODEL_##Code)
| ^
/transmission/gtk/GtkCompat.h:42:41: note: expanded from macro 'IF_GTKMM4'
42 | #define IF_GTKMM4(ThenValue, ElseValue) ThenValue
| ^
```

- Using the non-throw variant of `std::filesystem::last_write_time()` on Visual Studio 2022. Running clang-tidy 20.1.8.

Example output:
```
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include\xfilesystem_abi.h:132:1: warning: The value '33' provided to the cast expression is not in the valid range of values for '__std_fs_stats_flags' [clang-analyzer-optin.core.EnumCastOutOfRange]
132 | _BITMASK_OPS(_EMPTY_ARGUMENT, __std_fs_stats_flags)
| ^
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include\type_traits:2212:16: note: expanded from macro '_BITMASK_OPS'
2212 | return static_cast<_BITMASK>(static_cast<_IntTy>(_Left) | static_cast<_IntTy>(_Right)); \
| ^
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include\xfilesystem_abi.h:117:12: note: enum declared here
117 | enum class __std_fs_stats_flags : unsigned long {
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118 | _None = 0,
| ~~~~~~~~~~
119 |
120 | _Follow_symlinks = 0x01, // resolve symlink
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
121 | _Attributes = 0x02, // read/has attributes
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122 | _Reparse_tag = 0x04, // read/has reparse_tag; may not be combined with _Follow_symlinks
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123 | _File_size = 0x08, // read/has file size
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124 | _Link_count = 0x10, // read/has link count
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125 | _Last_write_time = 0x20, // read/has last write time
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126 |
127 | _All_data = _Attributes | _Reparse_tag | _File_size | _Link_count | _Last_write_time
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
128 | };
| ~
D:\a\transmission\transmission\src\libtransmission\file.cc:251:27: note: Calling 'tr_sys_path_get_info'
251 | if (auto const info = tr_sys_path_get_info(folder); !info || !info->isFolder())
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\a\transmission\transmission\src\libtransmission\file.cc:86:25: note: '?' condition is false
86 | auto const status = (flags & TR_SYS_PATH_NO_FOLLOW) != 0 ? std::filesystem::symlink_status(filesystem_path, ec) :
| ^
D:\a\transmission\transmission\src\libtransmission\file.cc:89:9: note: Left side of '||' is false
89 | if (ec || status.type() == std::filesystem::file_type::not_found)
| ^
D:\a\transmission\transmission\src\libtransmission\file.cc:89:5: note: Taking false branch
89 | if (ec || status.type() == std::filesystem::file_type::not_found)
| ^
D:\a\transmission\transmission\src\libtransmission\file.cc:97:5: note: Taking false branch
97 | if (std::filesystem::is_regular_file(status))
| ^
D:\a\transmission\transmission\src\libtransmission\file.cc:107:10: note: Taking false branch
107 | else if (std::filesystem::is_directory(status))
| ^
D:\a\transmission\transmission\src\libtransmission\file.cc:118:24: note: Calling 'last_write_time'
118 | auto const ftime = std::filesystem::last_write_time(filesystem_path, ec);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include\filesystem:3966:24: note: Calling '_Last_write_time'
3966 | _Ec = _Make_ec(_Last_write_time(_Path, _Result));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include\filesystem:3944:37: note: Calling 'operator|'
3944 | _Path.c_str(), &_Stats, __std_fs_stats_flags::_Follow_symlinks | __std_fs_stats_flags::_Last_write_time);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

Contributor guide

Open the contributing guide

Research direction

Start with clang-tidy's handling of the clang-analyzer-optin.core.EnumCastOutOfRange checker and how system-header filtering is applied. Reproduce the report with the gtkmm operator| or Visual Studio filesystem examples, then add a regression test covering system headers with and without --system-headers. Done means the warning is suppressed by default for system headers and remains available when explicitly enabled.

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
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.