summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2019-09-05 11:37:40 +0000
committerHans Wennborg <hans@hanshq.net>2019-09-05 11:37:40 +0000
commit893b39c09b3735fcb3b8bf512f1bd64a8aaa184f (patch)
tree7d087a0e36c979ce963e4fa6f152fd5a3d53ce91
parent5fc381cf3e9fae6ada0e575f31eb96f35f43d6e4 (diff)
downloadclang-893b39c09b3735fcb3b8bf512f1bd64a8aaa184f.tar.gz
Merging r369760:
------------------------------------------------------------------------ r369760 | szelethus | 2019-08-23 16:21:13 +0200 (Fri, 23 Aug 2019) | 13 lines [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/branches/release_90@371058 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp16
-rw-r--r--test/Analysis/enum-cast-out-of-range.c34
-rw-r--r--test/Analysis/enum-cast-out-of-range.cpp10
3 files changed, 59 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index 736d80ef9e..a6539098c8 100644
--- a/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -91,6 +91,22 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const {
void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
CheckerContext &C) const {
+
+ // Only perform enum range check on casts where such checks are valid. For
+ // all other cast kinds (where enum range checks are unnecessary or invalid),
+ // just return immediately. TODO: The set of casts whitelisted for enum
+ // range checking may be incomplete. Better to add a missing cast kind to
+ // enable a missing check than to generate false negatives and have to remove
+ // those later.
+ switch (CE->getCastKind()) {
+ case CK_IntegralCast:
+ break;
+
+ default:
+ return;
+ break;
+ }
+
// Get the value of the expression to cast.
const llvm::Optional<DefinedOrUnknownSVal> ValueToCast =
C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>();
diff --git a/test/Analysis/enum-cast-out-of-range.c b/test/Analysis/enum-cast-out-of-range.c
new file mode 100644
index 0000000000..03e1100c38
--- /dev/null
+++ b/test/Analysis/enum-cast-out-of-range.c
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
+// RUN: -verify %s
+
+enum En_t {
+ En_0 = -4,
+ En_1,
+ En_2 = 1,
+ En_3,
+ En_4 = 4
+};
+
+void unscopedUnspecifiedCStyle() {
+ enum En_t Below = (enum En_t)(-5); // expected-warning {{not in the valid range}}
+ enum En_t NegVal1 = (enum En_t)(-4); // OK.
+ enum En_t NegVal2 = (enum En_t)(-3); // OK.
+ enum En_t InRange1 = (enum En_t)(-2); // expected-warning {{not in the valid range}}
+ enum En_t InRange2 = (enum En_t)(-1); // expected-warning {{not in the valid range}}
+ enum En_t InRange3 = (enum En_t)(0); // expected-warning {{not in the valid range}}
+ enum En_t PosVal1 = (enum En_t)(1); // OK.
+ enum En_t PosVal2 = (enum En_t)(2); // OK.
+ enum En_t InRange4 = (enum En_t)(3); // expected-warning {{not in the valid range}}
+ enum En_t PosVal3 = (enum En_t)(4); // OK.
+ enum En_t Above = (enum En_t)(5); // expected-warning {{not in the valid range}}
+}
+
+enum En_t unused;
+void unusedExpr() {
+ // Following line is not something that EnumCastOutOfRangeChecker should
+ // evaluate. Checker should either ignore this line or process it without
+ // producing any warnings. However, compilation will (and should) still
+ // generate a warning having nothing to do with this checker.
+ unused; // expected-warning {{expression result unused}}
+}
diff --git a/test/Analysis/enum-cast-out-of-range.cpp b/test/Analysis/enum-cast-out-of-range.cpp
index e77339b551..b600367f8c 100644
--- a/test/Analysis/enum-cast-out-of-range.cpp
+++ b/test/Analysis/enum-cast-out-of-range.cpp
@@ -150,7 +150,15 @@ void scopedSpecifiedCStyle() {
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}}
}
-void rangeContstrained1(int input) {
+unscoped_unspecified_t unused;
+void unusedExpr() {
+ // following line is not something that EnumCastOutOfRangeChecker should evaluate. checker should either ignore this line
+ // or process it without producing any warnings. However, compilation will (and should) still generate a warning having
+ // nothing to do with this checker.
+ unused; // expected-warning {{expression result unused}}
+}
+
+void rangeConstrained1(int input) {
if (input > -5 && input < 5)
auto value = static_cast<scoped_specified_t>(input); // OK. Being conservative, this is a possibly good value.
}