Author: Balazs Benics Date: 2025-05-25T11:59:50+02:00 New Revision: 9a440f84773c56d3803f330774acb2b4f471d5b4
URL: https://github.com/llvm/llvm-project/commit/9a440f84773c56d3803f330774acb2b4f471d5b4 DIFF: https://github.com/llvm/llvm-project/commit/9a440f84773c56d3803f330774acb2b4f471d5b4.diff LOG: [analyzer] Ignore [[clang::flag_enum]] enums in the EnumCastOutOfRange checker (#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. Ideally, we should still check the upper bounds but for simplicity let's not bother for now. Added: Modified: clang/docs/analyzer/checkers.rst clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp clang/test/Analysis/enum-cast-out-of-range.c clang/test/Analysis/enum-cast-out-of-range.cpp Removed: ################################################################################ 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@-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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits