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

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


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

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.

>From 8ddc451d9017bbf68c847008878c2c8436f95a46 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Fri, 23 May 2025 15:04:52 +0200
Subject: [PATCH] [analyzer] Ignore [[clang::flag_enum]] enums in the
 EnumCastOutOfRange checker

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.
---
 clang/docs/analyzer/checkers.rst                      |  6 +++++-
 .../Checkers/EnumCastOutOfRangeChecker.cpp            |  5 +++++
 clang/test/Analysis/enum-cast-out-of-range.c          | 11 +++++++++++
 clang/test/Analysis/enum-cast-out-of-range.cpp        | 11 +++++++++++
 4 files changed, 32 insertions(+), 1 deletion(-)

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;
+}



More information about the cfe-commits mailing list