diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index acca50e3df88b..d89f886a39b3f 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -364,6 +364,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints { if is_allowed(cx, left) || is_allowed(cx, right) { return; } + + // Allow comparing the results of signum() + if is_signum(cx, left) && is_signum(cx, right) { + return; + } + if let Some(name) = get_item_name(cx, expr) { let name = name.as_str(); if name == "eq" @@ -493,6 +499,25 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool { } } +// Return true if `expr` is the result of `signum()` invoked on a float value. +fn is_signum(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { + // The negation of a signum is still a signum + if let ExprKind::Unary(UnNeg, ref child_expr) = expr.node { + return is_signum(cx, &child_expr); + } + + if_chain! { + if let ExprKind::MethodCall(ref method_name, _, ref expressions) = expr.node; + if sym!(signum) == method_name.ident.name; + // Check that the receiver of the signum() is a float (expressions[0] is the receiver of + // the method call) + then { + return is_float(cx, &expressions[0]); + } + } + false +} + fn is_float(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { matches!(walk_ptrs_ty(cx.tables.expr_ty(expr)).sty, ty::Float(_)) } diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index 92d38527bbf1b..1ec8af3e38719 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -77,4 +77,23 @@ fn main() { let b: *const f32 = xs.as_ptr(); assert_eq!(a, b); // no errors + + // no errors - comparing signums is ok + let x32 = 3.21f32; + 1.23f32.signum() == x32.signum(); + 1.23f32.signum() == -(x32.signum()); + 1.23f32.signum() == 3.21f32.signum(); + + 1.23f32.signum() != x32.signum(); + 1.23f32.signum() != -(x32.signum()); + 1.23f32.signum() != 3.21f32.signum(); + + let x64 = 3.21f64; + 1.23f64.signum() == x64.signum(); + 1.23f64.signum() == -(x64.signum()); + 1.23f64.signum() == 3.21f64.signum(); + + 1.23f64.signum() != x64.signum(); + 1.23f64.signum() != -(x64.signum()); + 1.23f64.signum() != 3.21f64.signum(); }