Skip to content

Commit 9a440f8

Browse files
authored
[analyzer] Ignore [[clang::flag_enum]] enums in the EnumCastOutOfRange checker (#141232)
Resolves #76208 (comment) Quoting the docs of `[[clang::flag_enum]]`: https://clang.llvm.org/docs/AttributeReference.html#flag-enum > This attribute can be added to an enumerator to signal to the compiler that it > is intended to be used as a flag type. This will cause the compiler to assume > that the range of the type includes all of the values that you can get by > manipulating bits of the enumerator when issuing warnings. Ideally, we should still check the upper bounds but for simplicity let's not bother for now.
1 parent bc0c4db commit 9a440f8

File tree

4 files changed

+32
-1
lines changed

4 files changed

+32
-1
lines changed

clang/docs/analyzer/checkers.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,11 @@ enumerators at all.
773773
**Limitations**
774774
775775
This checker does not accept the coding pattern where an enum type is used to
776-
store combinations of flag values:
776+
store combinations of flag values.
777+
Such enums should be annotated with the `__attribute__((flag_enum))` or by the
778+
`[[clang::flag_enum]]` attribute to signal this intent. Refer to the
779+
`documentation <https://clang.llvm.org/docs/AttributeReference.html#flag-enum>`_
780+
of this Clang attribute.
777781
778782
.. code-block:: cpp
779783

clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
// enumeration value
2020
//===----------------------------------------------------------------------===//
2121

22+
#include "clang/AST/Attr.h"
2223
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
2324
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2425
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -149,6 +150,10 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
149150
// function to handle this.
150151
const EnumDecl *ED = T->castAs<EnumType>()->getDecl();
151152

153+
// [[clang::flag_enum]] annotated enums are by definition should be ignored.
154+
if (ED->hasAttr<FlagEnumAttr>())
155+
return;
156+
152157
EnumValueVector DeclValues = getDeclValuesForEnum(ED);
153158

154159
// If the declarator list is empty, bail out.

clang/test/Analysis/enum-cast-out-of-range.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,14 @@ void testTrackExpression(int i) {
6464
(void)(enum En_t)(i); // expected-warning {{not in the valid range of values for 'En_t'}}
6565
// expected-note@-1 {{not in the valid range of values for 'En_t'}}
6666
}
67+
68+
enum __attribute__((flag_enum)) FlagEnum {
69+
FE_BIT_1 = 1 << 0,
70+
FE_BIT_2 = 1 << 1,
71+
FE_BIT_3 = 1 << 2,
72+
};
73+
74+
void testFlagEnum_gh_76208(void) {
75+
enum FlagEnum First2BitsSet = (enum FlagEnum)(FE_BIT_1 | FE_BIT_2); // no-warning: Enums with the attribute 'flag_enum' are not checked
76+
(void)First2BitsSet;
77+
}

clang/test/Analysis/enum-cast-out-of-range.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,14 @@ void foo() {
230230

231231
ignore_unused(c, x, d);
232232
}
233+
234+
enum [[clang::flag_enum]] FlagEnum {
235+
FE_BIT_1 = 1 << 0,
236+
FE_BIT_2 = 1 << 1,
237+
FE_BIT_3 = 1 << 2,
238+
};
239+
240+
void testFlagEnum_gh_76208(void) {
241+
FlagEnum First2BitsSet = (FlagEnum)(FE_BIT_1 | FE_BIT_2); // no-warning: Enums with the attribute 'flag_enum' are not checked
242+
(void)First2BitsSet;
243+
}

0 commit comments

Comments
 (0)