Skip to content

Commit

Permalink
[clang][analyzer] Fix empty enum handling in EnumCastOutOfRange checker
Browse files Browse the repository at this point in the history
The alpha.cplusplus.EnumCastOutOfRange checker previously gave many
false positives because a warning was given if the initializer value
did not appear in the enumerator list.
The strict handling caused std::byte to always give a warning, as it
is implemented as an enum class without any declarators.

Reviewed By: donat.nagy, steakhal

Differential Revision: https://reviews.llvm.org/D153954
  • Loading branch information
Endre Fülöp committed Aug 9, 2023
1 parent b808648 commit 90c1f51
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
const EnumDecl *ED = T->castAs<EnumType>()->getDecl();

EnumValueVector DeclValues = getDeclValuesForEnum(ED);

// If the declarator list is empty, bail out.
// Every initialization an enum with a fixed underlying type but without any
// enumerators would produce a warning if we were to continue at this point.
// The most notable example is std::byte in the C++17 standard library.
if (DeclValues.size() == 0)
return;

// Check if any of the enum values possibly match.
bool PossibleValueMatch = llvm::any_of(
DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));
Expand Down
17 changes: 17 additions & 0 deletions clang/test/Analysis/enum-cast-out-of-range.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,20 @@ void enumBitFieldAssignment() {
s.E = static_cast<unscoped_unspecified_t>(4); // OK.
s.E = static_cast<unscoped_unspecified_t>(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
}


enum class empty_unspecified {};

enum class empty_specified: char {};

enum class empty_specified_unsigned: unsigned char {};

void ignore_unused(...);

void empty_enums_init_with_zero_should_not_warn() {
auto eu = static_cast<empty_unspecified>(0); //should always be OK to zero initialize any enum
auto ef = static_cast<empty_specified>(0);
auto efu = static_cast<empty_specified_unsigned>(0);

ignore_unused(eu, ef, efu);
}

0 comments on commit 90c1f51

Please sign in to comment.