36
36
#include " clang/Basic/LangOptions.h"
37
37
#include " clang/Basic/SourceLocation.h"
38
38
#include " clang/Basic/Specifiers.h"
39
+ #include " llvm/ADT/APFloat.h"
39
40
#include " llvm/ADT/APInt.h"
40
41
#include " llvm/ADT/APSInt.h"
41
42
#include " llvm/ADT/ArrayRef.h"
@@ -70,19 +71,19 @@ static SourceLocation GetEndLoc(Decl *D) {
70
71
return D->getLocation ();
71
72
}
72
73
73
- // / Returns true on constant values based around a single IntegerLiteral.
74
- // / Allow for use of parentheses, integer casts, and negative signs.
75
- // / FIXME: it would be good to unify this function with
76
- // / getIntegerLiteralSubexpressionValue at some point given the similarity
77
- // / between the functions.
74
+ // / Returns true on constant values based around a single IntegerLiteral,
75
+ // / CharacterLiteral, or FloatingLiteral. Allow for use of parentheses, integer
76
+ // / casts, and negative signs.
78
77
79
- static bool IsIntegerLiteralConstantExpr (const Expr *E) {
78
+ static bool IsLiteralConstantExpr (const Expr *E) {
80
79
// Allow parentheses
81
80
E = E->IgnoreParens ();
82
81
83
- // Allow conversions to different integer kind.
82
+ // Allow conversions to different integer kind, and integer to floating point
83
+ // (to account for float comparing with int).
84
84
if (const auto *CE = dyn_cast<CastExpr>(E)) {
85
- if (CE->getCastKind () != CK_IntegralCast)
85
+ if (CE->getCastKind () != CK_IntegralCast &&
86
+ CE->getCastKind () != CK_IntegralToFloating)
86
87
return false ;
87
88
E = CE->getSubExpr ();
88
89
}
@@ -93,16 +94,15 @@ static bool IsIntegerLiteralConstantExpr(const Expr *E) {
93
94
return false ;
94
95
E = UO->getSubExpr ();
95
96
}
96
-
97
- return isa<IntegerLiteral>(E);
97
+ return isa<IntegerLiteral, CharacterLiteral, FloatingLiteral>(E);
98
98
}
99
99
100
100
// / Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral
101
- // / constant expression or EnumConstantDecl from the given Expr. If it fails,
102
- // / returns nullptr.
103
- static const Expr *tryTransformToIntOrEnumConstant (const Expr *E) {
101
+ // / FloatingLiteral, CharacterLiteral or EnumConstantDecl from the given Expr.
102
+ // / If it fails, returns nullptr.
103
+ static const Expr *tryTransformToLiteralConstant (const Expr *E) {
104
104
E = E->IgnoreParens ();
105
- if (IsIntegerLiteralConstantExpr (E))
105
+ if (IsLiteralConstantExpr (E))
106
106
return E;
107
107
if (auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts ()))
108
108
return isa<EnumConstantDecl>(DR->getDecl ()) ? DR : nullptr ;
@@ -119,7 +119,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) {
119
119
BinaryOperatorKind Op = B->getOpcode ();
120
120
121
121
const Expr *MaybeDecl = B->getLHS ();
122
- const Expr *Constant = tryTransformToIntOrEnumConstant (B->getRHS ());
122
+ const Expr *Constant = tryTransformToLiteralConstant (B->getRHS ());
123
123
// Expr looked like `0 == Foo` instead of `Foo == 0`
124
124
if (Constant == nullptr ) {
125
125
// Flip the operator
@@ -133,7 +133,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) {
133
133
Op = BO_GE;
134
134
135
135
MaybeDecl = B->getRHS ();
136
- Constant = tryTransformToIntOrEnumConstant (B->getLHS ());
136
+ Constant = tryTransformToLiteralConstant (B->getLHS ());
137
137
}
138
138
139
139
return std::make_tuple (MaybeDecl, Op, Constant);
@@ -1082,10 +1082,10 @@ class CFGBuilder {
1082
1082
return std::nullopt;
1083
1083
}
1084
1084
1085
+ template <typename APFloatOrInt>
1085
1086
TryResult analyzeLogicOperatorCondition (BinaryOperatorKind Relation,
1086
- const llvm::APSInt &Value1,
1087
- const llvm::APSInt &Value2) {
1088
- assert (Value1.isSigned () == Value2.isSigned ());
1087
+ const APFloatOrInt &Value1,
1088
+ const APFloatOrInt &Value2) {
1089
1089
switch (Relation) {
1090
1090
default :
1091
1091
return TryResult ();
@@ -1170,82 +1170,120 @@ class CFGBuilder {
1170
1170
if (!areExprTypesCompatible (NumExpr1, NumExpr2))
1171
1171
return {};
1172
1172
1173
+ // Check that the two expressions are of the same type.
1173
1174
Expr::EvalResult L1Result, L2Result;
1174
- if (!NumExpr1->EvaluateAsInt (L1Result, *Context) ||
1175
- !NumExpr2->EvaluateAsInt (L2Result, *Context))
1176
- return {};
1177
-
1178
- llvm::APSInt L1 = L1Result.Val .getInt ();
1179
- llvm::APSInt L2 = L2Result.Val .getInt ();
1180
-
1181
- // Can't compare signed with unsigned or with different bit width.
1182
- if (L1.isSigned () != L2.isSigned () || L1.getBitWidth () != L2.getBitWidth ())
1175
+ if (!NumExpr1->EvaluateAsRValue (L1Result, *Context) ||
1176
+ !NumExpr2->EvaluateAsRValue (L2Result, *Context))
1183
1177
return {};
1184
1178
1185
- // Values that will be used to determine if result of logical
1186
- // operator is always true/false
1187
- const llvm::APSInt Values[] = {
1188
- // Value less than both Value1 and Value2
1189
- llvm::APSInt::getMinValue (L1.getBitWidth (), L1.isUnsigned ()),
1190
- // L1
1191
- L1,
1192
- // Value between Value1 and Value2
1193
- ((L1 < L2) ? L1 : L2) + llvm::APSInt (llvm::APInt (L1.getBitWidth (), 1 ),
1194
- L1.isUnsigned ()),
1195
- // L2
1196
- L2,
1197
- // Value greater than both Value1 and Value2
1198
- llvm::APSInt::getMaxValue (L1.getBitWidth (), L1.isUnsigned ()),
1199
- };
1200
-
1201
- // Check whether expression is always true/false by evaluating the following
1179
+ // Check whether expression is always true/false by evaluating the
1180
+ // following
1202
1181
// * variable x is less than the smallest literal.
1203
1182
// * variable x is equal to the smallest literal.
1204
1183
// * Variable x is between smallest and largest literal.
1205
1184
// * Variable x is equal to the largest literal.
1206
1185
// * Variable x is greater than largest literal.
1207
- bool AlwaysTrue = true , AlwaysFalse = true ;
1208
- // Track value of both subexpressions. If either side is always
1209
- // true/false, another warning should have already been emitted.
1210
- bool LHSAlwaysTrue = true , LHSAlwaysFalse = true ;
1211
- bool RHSAlwaysTrue = true , RHSAlwaysFalse = true ;
1212
- for (const llvm::APSInt &Value : Values) {
1213
- TryResult Res1, Res2;
1214
- Res1 = analyzeLogicOperatorCondition (BO1, Value, L1);
1215
- Res2 = analyzeLogicOperatorCondition (BO2, Value, L2);
1216
-
1217
- if (!Res1.isKnown () || !Res2.isKnown ())
1218
- return {};
1186
+ // This isn't technically correct, as it doesn't take into account the
1187
+ // possibility that the variable could be NaN. However, this is a very rare
1188
+ // case.
1189
+ auto AnalyzeConditions = [&](const auto &Values,
1190
+ const BinaryOperatorKind *BO1,
1191
+ const BinaryOperatorKind *BO2) -> TryResult {
1192
+ bool AlwaysTrue = true , AlwaysFalse = true ;
1193
+ // Track value of both subexpressions. If either side is always
1194
+ // true/false, another warning should have already been emitted.
1195
+ bool LHSAlwaysTrue = true , LHSAlwaysFalse = true ;
1196
+ bool RHSAlwaysTrue = true , RHSAlwaysFalse = true ;
1197
+
1198
+ for (const auto &Value : Values) {
1199
+ TryResult Res1 =
1200
+ analyzeLogicOperatorCondition (*BO1, Value, Values[1 ] /* L1 */ );
1201
+ TryResult Res2 =
1202
+ analyzeLogicOperatorCondition (*BO2, Value, Values[3 ] /* L2 */ );
1203
+
1204
+ if (!Res1.isKnown () || !Res2.isKnown ())
1205
+ return {};
1206
+
1207
+ const bool IsAnd = B->getOpcode () == BO_LAnd;
1208
+ const bool Combine = IsAnd ? (Res1.isTrue () && Res2.isTrue ())
1209
+ : (Res1.isTrue () || Res2.isTrue ());
1210
+
1211
+ AlwaysTrue &= Combine;
1212
+ AlwaysFalse &= !Combine;
1213
+
1214
+ LHSAlwaysTrue &= Res1.isTrue ();
1215
+ LHSAlwaysFalse &= Res1.isFalse ();
1216
+ RHSAlwaysTrue &= Res2.isTrue ();
1217
+ RHSAlwaysFalse &= Res2.isFalse ();
1218
+ }
1219
1219
1220
- if (B-> getOpcode () == BO_LAnd ) {
1221
- AlwaysTrue &= (Res1. isTrue () && Res2. isTrue ());
1222
- AlwaysFalse &= !(Res1. isTrue () && Res2. isTrue ());
1223
- } else {
1224
- AlwaysTrue &= (Res1. isTrue () || Res2. isTrue ());
1225
- AlwaysFalse &= !(Res1. isTrue () || Res2. isTrue () );
1220
+ if (AlwaysTrue || AlwaysFalse ) {
1221
+ if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1222
+ !RHSAlwaysFalse && BuildOpts. Observer ) {
1223
+ BuildOpts. Observer -> compareAlwaysTrue (B, AlwaysTrue);
1224
+ }
1225
+ return TryResult (AlwaysTrue );
1226
1226
}
1227
+ return {};
1228
+ };
1227
1229
1228
- LHSAlwaysTrue &= Res1.isTrue ();
1229
- LHSAlwaysFalse &= Res1.isFalse ();
1230
- RHSAlwaysTrue &= Res2.isTrue ();
1231
- RHSAlwaysFalse &= Res2.isFalse ();
1230
+ // Handle integer comparison.
1231
+ if (L1Result.Val .getKind () == APValue::Int &&
1232
+ L2Result.Val .getKind () == APValue::Int) {
1233
+ llvm::APSInt L1 = L1Result.Val .getInt ();
1234
+ llvm::APSInt L2 = L2Result.Val .getInt ();
1235
+
1236
+ // Can't compare signed with unsigned or with different bit width.
1237
+ if (L1.isSigned () != L2.isSigned () ||
1238
+ L1.getBitWidth () != L2.getBitWidth ())
1239
+ return {};
1240
+
1241
+ // Values that will be used to determine if result of logical
1242
+ // operator is always true/false
1243
+ const llvm::APSInt Values[] = {
1244
+ // Value less than both Value1 and Value2
1245
+ llvm::APSInt::getMinValue (L1.getBitWidth (), L1.isUnsigned ()),
1246
+ // L1
1247
+ L1,
1248
+ // Value between Value1 and Value2
1249
+ ((L1 < L2) ? L1 : L2) +
1250
+ llvm::APSInt (llvm::APInt (L1.getBitWidth (), 1 ), L1.isUnsigned ()),
1251
+ // L2
1252
+ L2,
1253
+ // Value greater than both Value1 and Value2
1254
+ llvm::APSInt::getMaxValue (L1.getBitWidth (), L1.isUnsigned ()),
1255
+ };
1256
+
1257
+ return AnalyzeConditions (Values, &BO1, &BO2);
1232
1258
}
1233
1259
1234
- if (AlwaysTrue || AlwaysFalse) {
1235
- if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1236
- !RHSAlwaysFalse && BuildOpts.Observer )
1237
- BuildOpts.Observer ->compareAlwaysTrue (B, AlwaysTrue);
1238
- return TryResult (AlwaysTrue);
1260
+ // Handle float comparison.
1261
+ if (L1Result.Val .getKind () == APValue::Float &&
1262
+ L2Result.Val .getKind () == APValue::Float) {
1263
+ llvm::APFloat L1 = L1Result.Val .getFloat ();
1264
+ llvm::APFloat L2 = L2Result.Val .getFloat ();
1265
+ llvm::APFloat MidValue = L1;
1266
+ MidValue.add (L2, llvm::APFloat::rmNearestTiesToEven);
1267
+ MidValue.divide (llvm::APFloat (MidValue.getSemantics (), " 2.0" ),
1268
+ llvm::APFloat::rmNearestTiesToEven);
1269
+
1270
+ const llvm::APFloat Values[] = {
1271
+ llvm::APFloat::getSmallest (L1.getSemantics (), true ), L1, MidValue, L2,
1272
+ llvm::APFloat::getLargest (L2.getSemantics (), false ),
1273
+ };
1274
+
1275
+ return AnalyzeConditions (Values, &BO1, &BO2);
1239
1276
}
1277
+
1240
1278
return {};
1241
1279
}
1242
1280
1243
1281
// / A bitwise-or with a non-zero constant always evaluates to true.
1244
1282
TryResult checkIncorrectBitwiseOrOperator (const BinaryOperator *B) {
1245
1283
const Expr *LHSConstant =
1246
- tryTransformToIntOrEnumConstant (B->getLHS ()->IgnoreParenImpCasts ());
1284
+ tryTransformToLiteralConstant (B->getLHS ()->IgnoreParenImpCasts ());
1247
1285
const Expr *RHSConstant =
1248
- tryTransformToIntOrEnumConstant (B->getRHS ()->IgnoreParenImpCasts ());
1286
+ tryTransformToLiteralConstant (B->getRHS ()->IgnoreParenImpCasts ());
1249
1287
1250
1288
if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1251
1289
return {};
0 commit comments