[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