mirror of https://github.com/rust-lang/rust.git
Tests passing for invalid_upcast_comparisons
This commit is contained in:
parent
c81edfc7b9
commit
8687949a29
115
src/types.rs
115
src/types.rs
|
@ -1,5 +1,4 @@
|
||||||
use reexport::*;
|
use reexport::*;
|
||||||
use rustc_const_eval::*;
|
|
||||||
use rustc::lint::*;
|
use rustc::lint::*;
|
||||||
use rustc::middle::def;
|
use rustc::middle::def;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
|
@ -657,7 +656,7 @@ fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr)
|
||||||
BiLe => Some((Rel::Le, lhs, rhs)),
|
BiLe => Some((Rel::Le, lhs, rhs)),
|
||||||
BiGt => Some((Rel::Lt, rhs, lhs)),
|
BiGt => Some((Rel::Lt, rhs, lhs)),
|
||||||
BiGe => Some((Rel::Le, rhs, lhs)),
|
BiGe => Some((Rel::Le, rhs, lhs)),
|
||||||
_ => return None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,7 +668,7 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs
|
||||||
|
|
||||||
let normalized = normalize_comparison(op, lhs, rhs);
|
let normalized = normalize_comparison(op, lhs, rhs);
|
||||||
if normalized.is_none() { return None; } // Could be an if let, but this prevents rightward drift
|
if normalized.is_none() { return None; } // Could be an if let, but this prevents rightward drift
|
||||||
let (rel, normalized_lhs, normalized_rhs) = normalized.unwrap();
|
let (rel, normalized_lhs, normalized_rhs) = normalized.expect("Unreachable-- is none check above");
|
||||||
|
|
||||||
let lx = detect_extreme_expr(cx, normalized_lhs);
|
let lx = detect_extreme_expr(cx, normalized_lhs);
|
||||||
let rx = detect_extreme_expr(cx, normalized_rhs);
|
let rx = detect_extreme_expr(cx, normalized_rhs);
|
||||||
|
@ -818,15 +817,15 @@ enum FullInt {
|
||||||
}
|
}
|
||||||
|
|
||||||
use std;
|
use std;
|
||||||
use self::FullInt::*;
|
use std::cmp::Ordering;
|
||||||
use std::cmp::Ordering::*;
|
|
||||||
|
|
||||||
impl FullInt {
|
impl FullInt {
|
||||||
|
#[allow(cast_sign_loss)]
|
||||||
fn cmp_s_u(s: &i64, u: &u64) -> std::cmp::Ordering {
|
fn cmp_s_u(s: &i64, u: &u64) -> std::cmp::Ordering {
|
||||||
if *s < 0 {
|
if *s < 0 {
|
||||||
Less
|
Ordering::Less
|
||||||
} else if *u > (i64::max_value() as u64) {
|
} else if *u > (i64::max_value() as u64) {
|
||||||
Greater
|
Ordering::Greater
|
||||||
} else {
|
} else {
|
||||||
(*s as u64).cmp(u)
|
(*s as u64).cmp(u)
|
||||||
}
|
}
|
||||||
|
@ -835,7 +834,7 @@ impl FullInt {
|
||||||
|
|
||||||
impl PartialEq for FullInt {
|
impl PartialEq for FullInt {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.cmp(other) == Equal
|
self.cmp(other) == Ordering::Equal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Eq for FullInt {}
|
impl Eq for FullInt {}
|
||||||
|
@ -843,46 +842,43 @@ impl Eq for FullInt {}
|
||||||
impl PartialOrd for FullInt {
|
impl PartialOrd for FullInt {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
Some(match (self, other) {
|
Some(match (self, other) {
|
||||||
(&S(ref s), &S(ref o)) => s.cmp(o),
|
(&FullInt::S(ref s), &FullInt::S(ref o)) => s.cmp(o),
|
||||||
(&U(ref s), &U(ref o)) => s.cmp(o),
|
(&FullInt::U(ref s), &FullInt::U(ref o)) => s.cmp(o),
|
||||||
(&S(ref s), &U(ref o)) => Self::cmp_s_u(s, o),
|
(&FullInt::S(ref s), &FullInt::U(ref o)) => Self::cmp_s_u(s, o),
|
||||||
(&U(ref s), &S(ref o)) => Self::cmp_s_u(o, s).reverse(),
|
(&FullInt::U(ref s), &FullInt::S(ref o)) => Self::cmp_s_u(o, s).reverse(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Ord for FullInt {
|
impl Ord for FullInt {
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
self.partial_cmp(other).unwrap()
|
self.partial_cmp(other).expect("partial_cmp for FullInt can never return None")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> {
|
fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> {
|
||||||
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
|
use rustc::middle::ty::TypeVariants::{TyInt, TyUint};
|
||||||
|
use syntax::ast::UintTy;
|
||||||
|
use syntax::ast::IntTy;
|
||||||
|
use std::*;
|
||||||
|
|
||||||
if let ExprCast(ref cast_exp,_) = expr.node {
|
if let ExprCast(ref cast_exp,_) = expr.node {
|
||||||
let cv = match const_eval::eval_const_expr_partial(cx.tcx, cast_exp, ExprTypeChecked, None) {
|
match cx.tcx.expr_ty(cast_exp).sty {
|
||||||
Ok(val) => val,
|
TyInt(int_ty) => Some(match int_ty {
|
||||||
Err(_) => return None,
|
IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)),
|
||||||
};
|
IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)),
|
||||||
|
IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)),
|
||||||
if let Integral(const_int) = cv {
|
IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)),
|
||||||
Some(match const_int {
|
IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)),
|
||||||
I8(_) => (S(i8::min_value() as i64), S(i8::max_value() as i64)),
|
}),
|
||||||
I16(_) => (S(i16::min_value() as i64), S(i16::max_value() as i64)),
|
TyUint(uint_ty) => Some(match uint_ty {
|
||||||
I32(_) => (S(i32::min_value() as i64), S(i32::max_value() as i64)),
|
UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)),
|
||||||
Isize(_) |
|
UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)),
|
||||||
I64(_) |
|
UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)),
|
||||||
InferSigned(_) => (S(i64::max_value()), S(i64::max_value())),
|
UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)),
|
||||||
U8(_) => (U(u8::min_value() as u64), U(u8::max_value() as u64)),
|
UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)),
|
||||||
U16(_) => (U(u16::min_value() as u64), U(u16::max_value() as u64)),
|
}),
|
||||||
U32(_) => (U(u32::min_value() as u64), U(u32::max_value() as u64)),
|
_ => None,
|
||||||
Usize(_) |
|
|
||||||
U64(_) |
|
|
||||||
Infer(_) => (U(u64::max_value()), U(u64::max_value())),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -891,35 +887,36 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
|
||||||
|
|
||||||
fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
|
fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
|
||||||
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
|
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
|
||||||
|
use rustc_const_eval::*;
|
||||||
|
|
||||||
match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) {
|
match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
if let Integral(const_int) = val {
|
if let Integral(const_int) = val {
|
||||||
Some(match const_int {
|
Some(match const_int {
|
||||||
I8(x) => S(x as i64),
|
I8(x) => FullInt::S(x as i64),
|
||||||
I16(x) => S(x as i64),
|
I16(x) => FullInt::S(x as i64),
|
||||||
I32(x) => S(x as i64),
|
I32(x) => FullInt::S(x as i64),
|
||||||
Isize(x) => S(match x {
|
Isize(x) => FullInt::S(match x {
|
||||||
Is32(x_) => x_ as i64,
|
Is32(x_) => x_ as i64,
|
||||||
Is64(x_) => x_
|
Is64(x_) => x_
|
||||||
}),
|
}),
|
||||||
I64(x) => S(x),
|
I64(x) => FullInt::S(x),
|
||||||
InferSigned(x) => S(x as i64),
|
InferSigned(x) => FullInt::S(x as i64),
|
||||||
U8(x) => U(x as u64),
|
U8(x) => FullInt::U(x as u64),
|
||||||
U16(x) => U(x as u64),
|
U16(x) => FullInt::U(x as u64),
|
||||||
U32(x) => U(x as u64),
|
U32(x) => FullInt::U(x as u64),
|
||||||
Usize(x) => U(match x {
|
Usize(x) => FullInt::U(match x {
|
||||||
Us32(x_) => x_ as u64,
|
Us32(x_) => x_ as u64,
|
||||||
Us64(x_) => x_,
|
Us64(x_) => x_,
|
||||||
}),
|
}),
|
||||||
U64(x) => U(x),
|
U64(x) => FullInt::U(x),
|
||||||
Infer(x) => U(x as u64),
|
Infer(x) => FullInt::U(x as u64),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => return None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,12 +925,14 @@ impl LateLintPass for InvalidUpcastComparisons {
|
||||||
if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node {
|
if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node {
|
||||||
let normalized = normalize_comparison(cmp.node, lhs, rhs);
|
let normalized = normalize_comparison(cmp.node, lhs, rhs);
|
||||||
if normalized.is_none() { return; }
|
if normalized.is_none() { return; }
|
||||||
let (rel, normalized_lhs, normalized_rhs) = normalized.unwrap();
|
let (rel, normalized_lhs, normalized_rhs) = normalized.expect("Unreachable-- is none check above");
|
||||||
|
|
||||||
let norm_lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
|
let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
|
||||||
let norm_rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
|
let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
|
||||||
|
|
||||||
if let Some(nlb) = norm_lhs_bounds {
|
let msg = "Because of the numeric bounds prior to casting, this expression is always ";
|
||||||
|
|
||||||
|
if let Some(nlb) = lhs_bounds {
|
||||||
if let Some(norm_rhs_val) = node_as_const_fullint(cx, normalized_rhs) {
|
if let Some(norm_rhs_val) = node_as_const_fullint(cx, normalized_rhs) {
|
||||||
if match rel {
|
if match rel {
|
||||||
Rel::Lt => nlb.1 < norm_rhs_val,
|
Rel::Lt => nlb.1 < norm_rhs_val,
|
||||||
|
@ -942,7 +941,7 @@ impl LateLintPass for InvalidUpcastComparisons {
|
||||||
// Expression is always true
|
// Expression is always true
|
||||||
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
||||||
expr.span,
|
expr.span,
|
||||||
&format!(""));
|
&format!("{}{}.", msg, "true"));
|
||||||
} else if match rel {
|
} else if match rel {
|
||||||
Rel::Lt => nlb.0 >= norm_rhs_val,
|
Rel::Lt => nlb.0 >= norm_rhs_val,
|
||||||
Rel::Le => nlb.0 > norm_rhs_val,
|
Rel::Le => nlb.0 > norm_rhs_val,
|
||||||
|
@ -950,10 +949,10 @@ impl LateLintPass for InvalidUpcastComparisons {
|
||||||
// Expression is always false
|
// Expression is always false
|
||||||
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
||||||
expr.span,
|
expr.span,
|
||||||
&format!(""));
|
&format!("{}{}.", msg, "false"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(nrb) = norm_rhs_bounds {
|
} else if let Some(nrb) = rhs_bounds {
|
||||||
if let Some(norm_lhs_val) = node_as_const_fullint(cx, normalized_lhs) {
|
if let Some(norm_lhs_val) = node_as_const_fullint(cx, normalized_lhs) {
|
||||||
if match rel {
|
if match rel {
|
||||||
Rel::Lt => norm_lhs_val < nrb.0,
|
Rel::Lt => norm_lhs_val < nrb.0,
|
||||||
|
@ -962,7 +961,7 @@ impl LateLintPass for InvalidUpcastComparisons {
|
||||||
// Expression is always true
|
// Expression is always true
|
||||||
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
||||||
expr.span,
|
expr.span,
|
||||||
&format!(""));
|
&format!("{}{}.", msg, "true"));
|
||||||
} else if match rel {
|
} else if match rel {
|
||||||
Rel::Lt => norm_lhs_val >= nrb.1,
|
Rel::Lt => norm_lhs_val >= nrb.1,
|
||||||
Rel::Le => norm_lhs_val > nrb.1,
|
Rel::Le => norm_lhs_val > nrb.1,
|
||||||
|
@ -970,7 +969,7 @@ impl LateLintPass for InvalidUpcastComparisons {
|
||||||
// Expression is always false
|
// Expression is always false
|
||||||
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
cx.span_lint(INVALID_UPCAST_COMPARISONS,
|
||||||
expr.span,
|
expr.span,
|
||||||
&format!(""));
|
&format!("{}{}.", msg, "false"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,13 @@ fn main() {
|
||||||
let zero: u32 = 0;
|
let zero: u32 = 0;
|
||||||
let u8_max: u8 = 255;
|
let u8_max: u8 = 255;
|
||||||
|
|
||||||
(u8_max as u32) > 300; //~ERROR
|
(u8_max as u32) > 300; //~ERROR Because of the numeric bounds prior to casting, this expression is always false.
|
||||||
(u8_max as u32) > 20;
|
(u8_max as u32) > 20;
|
||||||
|
|
||||||
(zero as i32) < -5; //~ERROR
|
(zero as i32) < -5; //~ERROR Because of the numeric bounds prior to casting, this expression is always false.
|
||||||
(zero as i32) < 10;
|
(zero as i32) < 10;
|
||||||
|
|
||||||
|
-5 < (zero as i32); //~ERROR Because of the numeric bounds prior to casting, this expression is always true.
|
||||||
|
0 <= (zero as i32); //~ERROR Because of the numeric bounds prior to casting, this expression is always true.
|
||||||
|
0 < (zero as i32);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue