Merge pull request #2849 from mikerite/issue_2741

Fix #2741
This commit is contained in:
Oliver Schneider 2018-06-26 11:08:19 +02:00 committed by GitHub
commit 0de3f36a02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 20 deletions

View file

@ -122,21 +122,32 @@ impl Hash for Constant {
}
}
impl PartialOrd for Constant {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
impl Constant {
pub fn partial_cmp(tcx: TyCtxt, cmp_type: &ty::TypeVariants, left: &Self, right: &Self) -> Option<Ordering> {
match (left, right) {
(&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)),
(&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)),
(&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)),
(&Constant::Int(l), &Constant::Int(r)) => {
if let ty::TyInt(int_ty) = *cmp_type {
Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
} else {
Some(l.cmp(&r))
}
},
(&Constant::F64(l), &Constant::F64(r)) => l.partial_cmp(&r),
(&Constant::F32(l), &Constant::F32(r)) => l.partial_cmp(&r),
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) | (&Constant::Vec(ref l), &Constant::Vec(ref r)) => {
l.partial_cmp(r)
},
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => match lv.partial_cmp(rv) {
Some(Equal) => Some(ls.cmp(rs)),
x => x,
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) | (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l
.iter()
.zip(r.iter())
.map(|(li, ri)| Constant::partial_cmp(tcx, cmp_type, li, ri))
.find(|r| r.map_or(true, |o| o != Ordering::Equal))
.unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => {
match Constant::partial_cmp(tcx, cmp_type, lv, rv) {
Some(Equal) => Some(ls.cmp(rs)),
x => x,
}
},
_ => None, // TODO: Are there any useful inter-type orderings?
}

View file

@ -1,8 +1,8 @@
use crate::consts::{constant_simple, Constant};
use rustc::lint::*;
use rustc::hir::*;
use std::cmp::{Ordering, PartialOrd};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
use rustc::hir::*;
use rustc::lint::*;
use std::cmp::Ordering;
/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are
/// used to clamp values, but switched so that the result is constant.
@ -36,14 +36,22 @@ impl LintPass for MinMaxPass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
if let Some((inner_max, inner_c, _)) = min_max(cx, oe) {
if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) {
if outer_max == inner_max {
return;
}
match (outer_max, outer_c.partial_cmp(&inner_c)) {
match (
outer_max,
Constant::partial_cmp(cx.tcx, &cx.tables.expr_ty(ie).sty, &outer_c, &inner_c),
) {
(_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
_ => {
span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result");
span_lint(
cx,
MIN_MAX,
expr.span,
"this min/max combination leads to constant result",
);
},
}
}

View file

@ -23,6 +23,9 @@ fn main() {
min(1, max(LARGE, x)); // no error, we don't lookup consts here
let y = 2isize;
min(max(y, -1), 3);
let s;
s = "Hello";

View file

@ -31,15 +31,15 @@ error: this min/max combination leads to constant result
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this min/max combination leads to constant result
--> $DIR/min_max.rs:29:5
--> $DIR/min_max.rs:32:5
|
29 | min("Apple", max("Zoo", s));
32 | min("Apple", max("Zoo", s));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this min/max combination leads to constant result
--> $DIR/min_max.rs:30:5
--> $DIR/min_max.rs:33:5
|
30 | max(min(s, "Apple"), "Zoo");
33 | max(min(s, "Apple"), "Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors