Merge pull request #2203 from clippered/float_cmp_const
Fix #1142 float constant comparison lint
This commit is contained in:
@@ -367,6 +367,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||||||
arithmetic::INTEGER_ARITHMETIC,
|
arithmetic::INTEGER_ARITHMETIC,
|
||||||
array_indexing::INDEXING_SLICING,
|
array_indexing::INDEXING_SLICING,
|
||||||
assign_ops::ASSIGN_OPS,
|
assign_ops::ASSIGN_OPS,
|
||||||
|
misc::FLOAT_CMP_CONST,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
reg.register_lint_group("clippy_pedantic", vec.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
/// ```rust
|
||||||
|
/// const ONE == 1.00f64
|
||||||
|
/// x == ONE // where both are floats
|
||||||
|
/// ```
|
||||||
|
declare_restriction_lint! {
|
||||||
|
pub FLOAT_CMP_CONST,
|
||||||
|
"using `==` or `!=` on float constants instead of comparing difference with an epsilon"
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Pass;
|
pub struct Pass;
|
||||||
|
|
||||||
@@ -214,7 +236,8 @@ impl LintPass for Pass {
|
|||||||
REDUNDANT_PATTERN,
|
REDUNDANT_PATTERN,
|
||||||
USED_UNDERSCORE_BINDING,
|
USED_UNDERSCORE_BINDING,
|
||||||
SHORT_CIRCUIT_STATEMENT,
|
SHORT_CIRCUIT_STATEMENT,
|
||||||
ZERO_PTR
|
ZERO_PTR,
|
||||||
|
FLOAT_CMP_CONST
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,7 +357,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span_lint_and_then(cx, FLOAT_CMP, expr.span, "strict comparison of f32 or f64", |db| {
|
let (lint, msg) = if is_named_constant(cx, left) || is_named_constant(cx, right) {
|
||||||
|
(FLOAT_CMP_CONST, "strict comparison of f32 or f64 constant")
|
||||||
|
} else {
|
||||||
|
(FLOAT_CMP, "strict comparison of f32 or f64")
|
||||||
|
};
|
||||||
|
span_lint_and_then(cx, lint, expr.span, msg, |db| {
|
||||||
let lhs = Sugg::hir(cx, left, "..");
|
let lhs = Sugg::hir(cx, left, "..");
|
||||||
let rhs = Sugg::hir(cx, right, "..");
|
let rhs = Sugg::hir(cx, right, "..");
|
||||||
|
|
||||||
@@ -423,6 +451,14 @@ fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
|
||||||
|
if let Some((_, res)) = constant(cx, expr) {
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
|
fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
|
||||||
let parent_item = cx.tcx.hir.get_parent(expr.id);
|
let parent_item = cx.tcx.hir.get_parent(expr.id);
|
||||||
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
|
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
|
||||||
|
|||||||
45
tests/ui/float_cmp_const.rs
Normal file
45
tests/ui/float_cmp_const.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#![warn(float_cmp_const)]
|
||||||
|
#![allow(float_cmp)]
|
||||||
|
#![allow(unused, no_effect, unnecessary_operation)]
|
||||||
|
|
||||||
|
const ONE: f32 = 1.0;
|
||||||
|
const TWO: f32 = 2.0;
|
||||||
|
|
||||||
|
fn eq_one(x: f32) -> bool {
|
||||||
|
if x.is_nan() { false } else { x == ONE } // no error, inside "eq" fn
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// has errors
|
||||||
|
1f32 == ONE;
|
||||||
|
TWO == ONE;
|
||||||
|
TWO != ONE;
|
||||||
|
ONE + ONE == TWO;
|
||||||
|
1 as f32 == ONE;
|
||||||
|
|
||||||
|
let v = 0.9;
|
||||||
|
v == ONE;
|
||||||
|
v != ONE;
|
||||||
|
|
||||||
|
// no errors, lower than or greater than comparisons
|
||||||
|
v < ONE;
|
||||||
|
v > ONE;
|
||||||
|
v <= ONE;
|
||||||
|
v >= ONE;
|
||||||
|
|
||||||
|
// no errors, zero and infinity values
|
||||||
|
ONE != 0f32;
|
||||||
|
TWO == 0f32;
|
||||||
|
ONE != ::std::f32::INFINITY;
|
||||||
|
ONE == ::std::f32::NEG_INFINITY;
|
||||||
|
|
||||||
|
// no errors, but will warn float_cmp if '#![allow(float_cmp)]' above is removed
|
||||||
|
let w = 1.1;
|
||||||
|
v == w;
|
||||||
|
v != w;
|
||||||
|
v == 1.0;
|
||||||
|
v != 1.0;
|
||||||
|
}
|
||||||
85
tests/ui/float_cmp_const.stderr
Normal file
85
tests/ui/float_cmp_const.stderr
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:17:5
|
||||||
|
|
|
||||||
|
17 | 1f32 == ONE;
|
||||||
|
| ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error`
|
||||||
|
|
|
||||||
|
= note: `-D float-cmp-const` implied by `-D warnings`
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:17:5
|
||||||
|
|
|
||||||
|
17 | 1f32 == ONE;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:18:5
|
||||||
|
|
|
||||||
|
18 | TWO == ONE;
|
||||||
|
| ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
|
||||||
|
|
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:18:5
|
||||||
|
|
|
||||||
|
18 | TWO == ONE;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:19:5
|
||||||
|
|
|
||||||
|
19 | TWO != ONE;
|
||||||
|
| ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
|
||||||
|
|
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:19:5
|
||||||
|
|
|
||||||
|
19 | TWO != ONE;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:20:5
|
||||||
|
|
|
||||||
|
20 | ONE + ONE == TWO;
|
||||||
|
| ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error`
|
||||||
|
|
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:20:5
|
||||||
|
|
|
||||||
|
20 | ONE + ONE == TWO;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:21:5
|
||||||
|
|
|
||||||
|
21 | 1 as f32 == ONE;
|
||||||
|
| ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(1 as f32 - ONE).abs() < error`
|
||||||
|
|
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:21:5
|
||||||
|
|
|
||||||
|
21 | 1 as f32 == ONE;
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:24:5
|
||||||
|
|
|
||||||
|
24 | v == ONE;
|
||||||
|
| ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
|
||||||
|
|
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:24:5
|
||||||
|
|
|
||||||
|
24 | v == ONE;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: strict comparison of f32 or f64 constant
|
||||||
|
--> $DIR/float_cmp_const.rs:25:5
|
||||||
|
|
|
||||||
|
25 | v != ONE;
|
||||||
|
| ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
|
||||||
|
|
|
||||||
|
note: std::f32::EPSILON and std::f64::EPSILON are available.
|
||||||
|
--> $DIR/float_cmp_const.rs:25:5
|
||||||
|
|
|
||||||
|
25 | v != ONE;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
Reference in New Issue
Block a user