[clang] [analyzer] Ignore [[clang::flag_enum]] enums in the EnumCastOutOfRange checker (PR #141232)

via cfe-commits cfe-commits at lists.llvm.org
Fri May 23 06:20:28 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balazs Benics (steakhal)

<details>
<summary>Changes</summary>

Resolves https://github.com/llvm/llvm-project/issues/76208#issuecomment-2830854351

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
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<EnumType>()->getDecl();
 
+  // [[clang::flag_enum]] annotated enums are by definition should be ignored.
+  if (ED->hasAttr<FlagEnumAttr>())
+    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 at -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;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/141232


More information about the cfe-commits mailing list