Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.

Commit 6f044b2

Browse files
Kristof UmannGabor Marton
authored andcommitted
[analyzer] Avoid unnecessary enum range check on LValueToRValue casts
Summary: EnumCastOutOfRangeChecker should not perform enum range checks on LValueToRValue casts, since this type of cast does not actually change the underlying type. Performing the unnecessary check actually triggered an assertion failure deeper in EnumCastOutOfRange for certain input (which is captured in the accompanying test code). Reviewers: #clang, Szelethus, gamesh411, NoQ Reviewed By: Szelethus, gamesh411, NoQ Subscribers: NoQ, gamesh411, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp, Charusso, bjope, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66014 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369760 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 6921816 commit 6f044b2

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,22 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const {
9292

9393
void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
9494
CheckerContext &C) const {
95+
96+
// Only perform enum range check on casts where such checks are valid. For
97+
// all other cast kinds (where enum range checks are unnecessary or invalid),
98+
// just return immediately. TODO: The set of casts whitelisted for enum
99+
// range checking may be incomplete. Better to add a missing cast kind to
100+
// enable a missing check than to generate false negatives and have to remove
101+
// those later.
102+
switch (CE->getCastKind()) {
103+
case CK_IntegralCast:
104+
break;
105+
106+
default:
107+
return;
108+
break;
109+
}
110+
95111
// Get the value of the expression to cast.
96112
const llvm::Optional<DefinedOrUnknownSVal> ValueToCast =
97113
C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>();
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_analyze_cc1 \
2+
// RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
3+
// RUN: -verify %s
4+
5+
enum En_t {
6+
En_0 = -4,
7+
En_1,
8+
En_2 = 1,
9+
En_3,
10+
En_4 = 4
11+
};
12+
13+
void unscopedUnspecifiedCStyle() {
14+
enum En_t Below = (enum En_t)(-5); // expected-warning {{not in the valid range}}
15+
enum En_t NegVal1 = (enum En_t)(-4); // OK.
16+
enum En_t NegVal2 = (enum En_t)(-3); // OK.
17+
enum En_t InRange1 = (enum En_t)(-2); // expected-warning {{not in the valid range}}
18+
enum En_t InRange2 = (enum En_t)(-1); // expected-warning {{not in the valid range}}
19+
enum En_t InRange3 = (enum En_t)(0); // expected-warning {{not in the valid range}}
20+
enum En_t PosVal1 = (enum En_t)(1); // OK.
21+
enum En_t PosVal2 = (enum En_t)(2); // OK.
22+
enum En_t InRange4 = (enum En_t)(3); // expected-warning {{not in the valid range}}
23+
enum En_t PosVal3 = (enum En_t)(4); // OK.
24+
enum En_t Above = (enum En_t)(5); // expected-warning {{not in the valid range}}
25+
}
26+
27+
enum En_t unused;
28+
void unusedExpr() {
29+
// Following line is not something that EnumCastOutOfRangeChecker should
30+
// evaluate. Checker should either ignore this line or process it without
31+
// producing any warnings. However, compilation will (and should) still
32+
// generate a warning having nothing to do with this checker.
33+
unused; // expected-warning {{expression result unused}}
34+
}

test/Analysis/enum-cast-out-of-range.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,15 @@ void scopedSpecifiedCStyle() {
150150
scoped_specified_t InvalidAfterRangeEnd = (scoped_specified_t)(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
151151
}
152152

153-
void rangeContstrained1(int input) {
153+
unscoped_unspecified_t unused;
154+
void unusedExpr() {
155+
// following line is not something that EnumCastOutOfRangeChecker should evaluate. checker should either ignore this line
156+
// or process it without producing any warnings. However, compilation will (and should) still generate a warning having
157+
// nothing to do with this checker.
158+
unused; // expected-warning {{expression result unused}}
159+
}
160+
161+
void rangeConstrained1(int input) {
154162
if (input > -5 && input < 5)
155163
auto value = static_cast<scoped_specified_t>(input); // OK. Being conservative, this is a possibly good value.
156164
}

0 commit comments

Comments
 (0)