[analyzer] Ignore [[clang::flag_enum]] enums in the EnumCastOutOfRange checker by steakhal · Pull Request #141232 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-static-analyzer-1
Author: Balazs Benics (steakhal)
Changes
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.
Full diff: https://github.com/llvm/llvm-project/pull/141232.diff
4 Files Affected:
- (modified) clang/docs/analyzer/checkers.rst (+5-1)
- (modified) clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp (+5)
- (modified) clang/test/Analysis/enum-cast-out-of-range.c (+11)
- (modified) clang/test/Analysis/enum-cast-out-of-range.cpp (+11)
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index c2ae80c47eca1..26c5028e04955 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -773,7 +773,11 @@ enumerators at all. Limitations
This checker does not accept the coding pattern where an enum type is used to
-store combinations of flag values:
+store combinations of flag values.
+Such enums should be annotated with the __attribute__((flag_enum)) or by the
+[[clang::flag_enum]] attribute to signal this intent. Refer to the
+documentation <https://clang.llvm.org/docs/AttributeReference.html#flag-enum>_
+of this Clang attribute.
.. code-block:: cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp index 0fa20428c1b56..355e82e465e82 100644 --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -19,6 +19,7 @@ // enumeration value //===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -149,6 +150,10 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE, // function to handle this. const EnumDecl *ED = T->castAs()->getDecl();
// [[clang::flag_enum]] annotated enums are by definition should be ignored.
if (ED->hasAttr())
return;
EnumValueVector DeclValues = getDeclValuesForEnum(ED);
// If the declarator list is empty, bail out.
diff --git a/clang/test/Analysis/enum-cast-out-of-range.c b/clang/test/Analysis/enum-cast-out-of-range.c index a6eef92f418d1..f9f7aac5ae1b7 100644 --- a/clang/test/Analysis/enum-cast-out-of-range.c +++ b/clang/test/Analysis/enum-cast-out-of-range.c @@ -64,3 +64,14 @@ void testTrackExpression(int i) { (void)(enum En_t)(i); // expected-warning {{not in the valid range of values for 'En_t'}} // expected-note@-1 {{not in the valid range of values for 'En_t'}} } + +enum attribute((flag_enum)) FlagEnum {
FE_BIT_1 = 1 << 0,
FE_BIT_2 = 1 << 1,
FE_BIT_3 = 1 << 2, +};
+void testFlagEnum_gh_76208(void) {
enum FlagEnum First2BitsSet = (enum FlagEnum)(FE_BIT_1 | FE_BIT_2); // no-warning: Enums with the attribute 'flag_enum' are not checked
(void)First2BitsSet; +} diff --git a/clang/test/Analysis/enum-cast-out-of-range.cpp b/clang/test/Analysis/enum-cast-out-of-range.cpp index a5ac4f3fd0567..81763ae893135 100644 --- a/clang/test/Analysis/enum-cast-out-of-range.cpp +++ b/clang/test/Analysis/enum-cast-out-of-range.cpp @@ -230,3 +230,14 @@ void foo() {
ignore_unused(c, x, d);
} + +enum [[clang::flag_enum]] FlagEnum {
- FE_BIT_1 = 1 << 0,
- FE_BIT_2 = 1 << 1,
- FE_BIT_3 = 1 << 2, +};
- +void testFlagEnum_gh_76208(void) {
- FlagEnum First2BitsSet = (FlagEnum)(FE_BIT_1 | FE_BIT_2); // no-warning: Enums with the attribute 'flag_enum' are not checked
- (void)First2BitsSet; +}