Skip to content

Commit 7a32c28

Browse files
author
Michael Wright
committed
Fix #2741
1 parent 45bab50 commit 7a32c28

File tree

3 files changed

+35
-9
lines changed

3 files changed

+35
-9
lines changed

clippy_lints/src/minmax.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::consts::{constant_simple, Constant};
2-
use rustc::lint::*;
2+
use crate::utils::{match_def_path, opt_def_id, paths, sext, span_lint};
33
use rustc::hir::*;
4+
use rustc::lint::*;
5+
use rustc::ty::{self, TyCtxt};
46
use std::cmp::{Ordering, PartialOrd};
5-
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
67

78
/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are
89
/// used to clamp values, but switched so that the result is constant.
@@ -36,21 +37,43 @@ impl LintPass for MinMaxPass {
3637
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass {
3738
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
3839
if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
39-
if let Some((inner_max, inner_c, _)) = min_max(cx, oe) {
40+
if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) {
4041
if outer_max == inner_max {
4142
return;
4243
}
43-
match (outer_max, outer_c.partial_cmp(&inner_c)) {
44+
match (
45+
outer_max,
46+
const_partial_cmp(cx.tcx, &outer_c, &inner_c, &cx.tables.expr_ty(ie).sty),
47+
) {
4448
(_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
4549
_ => {
46-
span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result");
50+
span_lint(
51+
cx,
52+
MIN_MAX,
53+
expr.span,
54+
"this min/max combination leads to constant result",
55+
);
4756
},
4857
}
4958
}
5059
}
5160
}
5261
}
5362

63+
// Constant::partial_cmp incorrectly orders signed integers
64+
fn const_partial_cmp(tcx: TyCtxt, a: &Constant, b: &Constant, expr_ty: &ty::TypeVariants) -> Option<Ordering> {
65+
match *expr_ty {
66+
ty::TyInt(int_ty) => {
67+
if let (&Constant::Int(a), &Constant::Int(b)) = (a, b) {
68+
Some(sext(tcx, a, int_ty).cmp(&sext(tcx, b, int_ty)))
69+
} else {
70+
None
71+
}
72+
},
73+
_ => a.partial_cmp(&b),
74+
}
75+
}
76+
5477
#[derive(PartialEq, Eq, Debug)]
5578
enum MinMax {
5679
Min,

tests/ui/min_max.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ fn main() {
2323

2424
min(1, max(LARGE, x)); // no error, we don't lookup consts here
2525

26+
let y = 2isize;
27+
min(max(y, -1), 3);
28+
2629
let s;
2730
s = "Hello";
2831

tests/ui/min_max.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ error: this min/max combination leads to constant result
3131
| ^^^^^^^^^^^^^^^^^^^^^^^
3232

3333
error: this min/max combination leads to constant result
34-
--> $DIR/min_max.rs:29:5
34+
--> $DIR/min_max.rs:32:5
3535
|
36-
29 | min("Apple", max("Zoo", s));
36+
32 | min("Apple", max("Zoo", s));
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838

3939
error: this min/max combination leads to constant result
40-
--> $DIR/min_max.rs:30:5
40+
--> $DIR/min_max.rs:33:5
4141
|
42-
30 | max(min(s, "Apple"), "Zoo");
42+
33 | max(min(s, "Apple"), "Zoo");
4343
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
4444

4545
error: aborting due to 7 previous errors

0 commit comments

Comments
 (0)