diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index 8949e4cc387..53d0d7cebaa 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -1,13 +1,9 @@ use rustc::lint::*; -use rustc::middle::const_val::ConstVal; use rustc::ty; -use rustc::ty::subst::Substs; -use rustc_const_eval::ConstContext; -use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc::hir; use syntax::ast::RangeLimits; use utils::{self, higher}; -use utils::const_to_u64; +use consts::{constant, Constant}; /// **What it does:** Checks for out of bounds array indexing with a constant /// index. @@ -63,29 +59,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { // Array with known size can be checked statically let ty = cx.tables.expr_ty(array); if let ty::TyArray(_, size) = ty.sty { - let size = ConstInt::Usize( - ConstUsize::new(const_to_u64(size), cx.sess().target.usize_ty).expect("array size is invalid"), - ); - let parent_item = cx.tcx.hir.get_parent(e.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - let constcx = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables); + let size = size.val.to_raw_bits().unwrap(); // Index is a constant uint - if let Ok(const_index) = constcx.eval(index) { - if let ConstVal::Integral(const_index) = const_index.val { - if size <= const_index { - utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); - } - - return; + if let Some((Constant::Int(const_index), _)) = constant(cx, index) { + if size <= const_index { + utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); } + + return; } // Index is a constant range if let Some(range) = higher::range(index) { - let start = range.start.map(|start| constcx.eval(start)).map(|v| v.ok()); - let end = range.end.map(|end| constcx.eval(end)).map(|v| v.ok()); + let start = range.start.map(|start| constant(cx, start).map(|(c, _)| c)); + let end = range.end.map(|end| constant(cx, end).map(|(c, _)| c)); if let Some((start, end)) = to_const_range(&start, &end, range.limits, size) { if start > size || end > size { @@ -114,43 +102,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { /// Returns an option containing a tuple with the start and end (exclusive) of /// the range. fn to_const_range( - start: &Option>, - end: &Option>, + start: &Option>, + end: &Option>, limits: RangeLimits, - array_size: ConstInt, -) -> Option<(ConstInt, ConstInt)> { + array_size: u128, +) -> Option<(u128, u128)> { let start = match *start { - Some(Some(&ty::Const { - val: ConstVal::Integral(x), - .. - })) => x, + Some(Some(Constant::Int(x))) => x, Some(_) => return None, - None => ConstInt::U8(0), + None => 0, }; let end = match *end { - Some(Some(&ty::Const { - val: ConstVal::Integral(x), - .. - })) => if limits == RangeLimits::Closed { - match x { - ConstInt::U8(_) => (x + ConstInt::U8(1)), - ConstInt::U16(_) => (x + ConstInt::U16(1)), - ConstInt::U32(_) => (x + ConstInt::U32(1)), - ConstInt::U64(_) => (x + ConstInt::U64(1)), - ConstInt::U128(_) => (x + ConstInt::U128(1)), - ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))), - ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))), - ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))), - ConstInt::I8(_) => (x + ConstInt::I8(1)), - ConstInt::I16(_) => (x + ConstInt::I16(1)), - ConstInt::I32(_) => (x + ConstInt::I32(1)), - ConstInt::I64(_) => (x + ConstInt::I64(1)), - ConstInt::I128(_) => (x + ConstInt::I128(1)), - ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))), - ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))), - ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))), - }.expect("such a big array is not realistic") + Some(Some(Constant::Int(x))) => if limits == RangeLimits::Closed { + x + 1 } else { x }, diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index f0ff27d4d63..7eb6477b269 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,11 +1,10 @@ use rustc::hir::*; -use rustc::hir::def::Def; use rustc::lint::*; -use rustc_const_eval::lookup_const_by_id; use syntax::ast::LitKind; use syntax::codemap::Span; use utils::{span_lint, span_lint_and_then}; use utils::sugg::Sugg; +use consts::{constant, Constant}; /// **What it does:** Checks for incompatible bit masks in comparisons. /// @@ -302,31 +301,8 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str } fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option { - use rustc::ty::subst::Substs; - match lit.node { - ExprLit(ref lit_ptr) => { - if let LitKind::Int(value, _) = lit_ptr.node { - Some(value) // TODO: Handle sign - } else { - None - } - }, - ExprPath(ref qpath) => { - let def = cx.tables.qpath_def(qpath, lit.hir_id); - if let Def::Const(def_id) = def { - lookup_const_by_id(cx.tcx, cx.param_env.and((def_id, Substs::empty()))).and_then(|(l, _ty)| { - let body = if let Some(id) = cx.tcx.hir.as_local_node_id(l) { - cx.tcx.mir_const_qualif(def_id); - cx.tcx.hir.body(cx.tcx.hir.body_owned_by(id)) - } else { - cx.tcx.extern_const_body(def_id).body - }; - fetch_int_literal(cx, &body.value) - }) - } else { - None - } - }, + match constant(cx, lit)?.0 { + Constant::Int(n) => Some(n), _ => None, } } diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index a99a56bc554..7c43cb668b3 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -2,19 +2,18 @@ use rustc::lint::LateContext; use rustc::hir::def::Def; -use rustc_const_eval::lookup_const_by_id; -use rustc_const_math::ConstInt; use rustc::hir::*; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, Instance}; use rustc::ty::subst::{Subst, Substs}; use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; use std::mem; use std::rc::Rc; -use syntax::ast::{FloatTy, LitKind, StrStyle}; +use syntax::ast::{FloatTy, LitKind}; use syntax::ptr::P; -use utils::const_to_u64; +use rustc::middle::const_val::ConstVal; +use utils::{sext, unsext, clip}; #[derive(Debug, Copy, Clone)] pub enum FloatWidth { @@ -36,15 +35,17 @@ impl From for FloatWidth { #[derive(Debug, Clone)] pub enum Constant { /// a String "abc" - Str(String, StrStyle), + Str(String), /// a Binary String b"abc" Binary(Rc>), /// a single char 'a' Char(char), - /// an integer, third argument is whether the value is negated - Int(ConstInt), - /// a float with given type - Float(String, FloatWidth), + /// an integer's bit representation + Int(u128), + /// an f32 + F32(f32), + /// an f64 + F64(f64), /// true or false Bool(bool), /// an array of constants @@ -58,20 +59,21 @@ pub enum Constant { impl PartialEq for Constant { fn eq(&self, other: &Self) -> bool { match (self, other) { - (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => ls == rs && l_sty == r_sty, + (&Constant::Str(ref ls), &Constant::Str(ref rs)) => ls == rs, (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, (&Constant::Char(l), &Constant::Char(r)) => l == r, - (&Constant::Int(l), &Constant::Int(r)) => { - l.is_negative() == r.is_negative() && l.to_u128_unchecked() == r.to_u128_unchecked() - }, - (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { + (&Constant::Int(l), &Constant::Int(r)) => l == r, + (&Constant::F64(l), &Constant::F64(r)) => { // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have // `Fw32 == Fw64` so don’t compare them - match (ls.parse::(), rs.parse::()) { - // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs - (Ok(l), Ok(r)) => unsafe { mem::transmute::(l) == mem::transmute::(r) }, - _ => false, - } + // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs + unsafe { mem::transmute::(l) == mem::transmute::(r) } + }, + (&Constant::F32(l), &Constant::F32(r)) => { + // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have + // `Fw32 == Fw64` so don’t compare them + // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs + unsafe { mem::transmute::(l as f64) == mem::transmute::(r as f64) } }, (&Constant::Bool(l), &Constant::Bool(r)) => l == r, (&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r, @@ -87,9 +89,8 @@ impl Hash for Constant { H: Hasher, { match *self { - Constant::Str(ref s, ref k) => { + Constant::Str(ref s) => { s.hash(state); - k.hash(state); }, Constant::Binary(ref b) => { b.hash(state); @@ -98,14 +99,13 @@ impl Hash for Constant { c.hash(state); }, Constant::Int(i) => { - i.to_u128_unchecked().hash(state); - i.is_negative().hash(state); + i.hash(state); }, - Constant::Float(ref f, _) => { - // don’t use the width here because of PartialEq implementation - if let Ok(f) = f.parse::() { - unsafe { mem::transmute::(f) }.hash(state); - } + Constant::F32(f) => { + unsafe { mem::transmute::(f as f64) }.hash(state); + }, + Constant::F64(f) => { + unsafe { mem::transmute::(f) }.hash(state); }, Constant::Bool(b) => { b.hash(state); @@ -124,25 +124,11 @@ impl Hash for Constant { impl PartialOrd for Constant { fn partial_cmp(&self, other: &Self) -> Option { match (self, other) { - (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => if l_sty == r_sty { - Some(ls.cmp(rs)) - } else { - None - }, + (&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::Float(ref ls, _), &Constant::Float(ref rs, _)) => { - match (ls.parse::(), rs.parse::()) { - (Ok(ref l), Ok(ref r)) => { - match (l.partial_cmp(r), l.is_sign_positive() == r.is_sign_positive()) { - // Check for comparison of -0.0 and 0.0 - (Some(Ordering::Equal), false) => None, - (x, _) => x, - } - }, - _ => None, - } - }, + (&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) @@ -157,63 +143,25 @@ impl PartialOrd for Constant { } /// parse a `LitKind` to a `Constant` -#[allow(cast_possible_wrap)] -pub fn lit_to_constant<'a, 'tcx>(lit: &LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, mut ty: Ty<'tcx>) -> Constant { +pub fn lit_to_constant<'a, 'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant { use syntax::ast::*; - use syntax::ast::LitIntType::*; - use rustc::ty::util::IntTypeExt; - if let ty::TyAdt(adt, _) = ty.sty { - if adt.is_enum() { - ty = adt.repr.discr_type().to_ty(tcx) - } - } match *lit { - LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), - LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), + LitKind::Str(ref is, _) => Constant::Str(is.to_string()), + LitKind::Byte(b) => Constant::Int(b as u128), LitKind::ByteStr(ref s) => Constant::Binary(Rc::clone(s)), LitKind::Char(c) => Constant::Char(c), - LitKind::Int(n, hint) => match (&ty.sty, hint) { - (&ty::TyInt(ity), _) | (_, Signed(ity)) => { - Constant::Int(ConstInt::new_signed_truncating(n as i128, ity, tcx.sess.target.isize_ty)) - }, - (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { - Constant::Int(ConstInt::new_unsigned_truncating(n as u128, uty, tcx.sess.target.usize_ty)) - }, + LitKind::Int(n, _) => Constant::Int(n), + LitKind::Float(ref is, _) | + LitKind::FloatUnsuffixed(ref is) => match ty.sty { + ty::TyFloat(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()), + ty::TyFloat(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()), _ => bug!(), }, - LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), - LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any), LitKind::Bool(b) => Constant::Bool(b), } } -fn constant_not(o: &Constant) -> Option { - use self::Constant::*; - match *o { - Bool(b) => Some(Bool(!b)), - Int(value) => (!value).ok().map(Int), - _ => None, - } -} - -fn constant_negate(o: Constant) -> Option { - use self::Constant::*; - match o { - Int(value) => (-value).ok().map(Int), - Float(is, ty) => Some(Float(neg_float_str(&is), ty)), - _ => None, - } -} - -fn neg_float_str(s: &str) -> String { - if s.starts_with('-') { - s[1..].to_owned() - } else { - format!("-{}", s) - } -} - pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { let mut cx = ConstEvalLateContext { tcx: lcx.tcx, @@ -255,19 +203,19 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { ExprPath(ref qpath) => self.fetch_path(qpath, e.hir_id), ExprBlock(ref block) => self.block(block), ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise), - ExprLit(ref lit) => Some(lit_to_constant(&lit.node, self.tcx, self.tables.expr_ty(e))), + ExprLit(ref lit) => Some(lit_to_constant(&lit.node, self.tables.expr_ty(e))), ExprArray(ref vec) => self.multi(vec).map(Constant::Vec), ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprRepeat(ref value, _) => { let n = match self.tables.expr_ty(e).sty { - ty::TyArray(_, n) => const_to_u64(n), + ty::TyArray(_, n) => n.val.to_raw_bits().expect("array length"), _ => span_bug!(e.span, "typeck error"), }; - self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) + self.expr(value).map(|v| Constant::Repeat(Box::new(v), n as u64)) }, ExprUnary(op, ref operand) => self.expr(operand).and_then(|o| match op { - UnNot => constant_not(&o), - UnNeg => constant_negate(o), + UnNot => self.constant_not(&o, self.tables.expr_ty(e)), + UnNeg => self.constant_negate(o, self.tables.expr_ty(e)), UnDeref => Some(o), }), ExprBinary(op, ref left, ref right) => self.binop(op, left, right), @@ -276,6 +224,42 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } } + fn constant_not(&self, o: &Constant, ty: ty::Ty) -> Option { + use self::Constant::*; + match *o { + Bool(b) => Some(Bool(!b)), + Int(value) => { + let mut value = !value; + match ty.sty { + ty::TyInt(ity) => Some(Int(unsext(self.tcx, value as i128, ity))), + ty::TyUint(ity) => Some(Int(clip(self.tcx, value, ity))), + _ => None, + } + }, + _ => None, + } + } + + fn constant_negate(&self, o: Constant, ty: ty::Ty) -> Option { + use self::Constant::*; + match o { + Int(value) => { + let ity = match ty.sty { + ty::TyInt(ity) => ity, + _ => return None, + }; + // sign extend + let value = sext(self.tcx, value, ity); + let value = value.checked_neg()?; + // clear unused bits + Some(Int(unsext(self.tcx, value, ity))) + }, + F32(f) => Some(F32(-f)), + F64(f) => Some(F64(-f)), + _ => None, + } + } + /// create `Some(Vec![..])` of all constants, unless there is any /// non-constant part fn multi(&mut self, vec: &[Expr]) -> Option> { @@ -295,27 +279,18 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } else { substs.subst(self.tcx, self.substs) }; - let param_env = self.param_env.and((def_id, substs)); - if let Some((def_id, substs)) = lookup_const_by_id(self.tcx, param_env) { - let mut cx = Self { - tcx: self.tcx, - tables: self.tcx.typeck_tables_of(def_id), - needed_resolution: false, - substs: substs, - param_env: param_env.param_env, - }; - let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - self.tcx.mir_const_qualif(def_id); - self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) - } else { - self.tcx.extern_const_body(def_id).body - }; - let ret = cx.expr(&body.value); - if ret.is_some() { - self.needed_resolution = true; - } - return ret; + let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs)?; + let gid = GlobalId { + instance, + promoted: None, + }; + use rustc::mir::interpret::GlobalId; + let result = self.tcx.const_eval(self.param_env.and(gid)).ok()?; + let ret = miri_to_const(self.tcx, result); + if ret.is_some() { + self.needed_resolution = true; } + return ret; }, _ => {}, } @@ -344,36 +319,127 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option { - let l = if let Some(l) = self.expr(left) { - l - } else { - return None; - }; + let l = self.expr(left)?; let r = self.expr(right); - match (op.node, l, r) { - (BiAdd, Constant::Int(l), Some(Constant::Int(r))) => (l + r).ok().map(Constant::Int), - (BiSub, Constant::Int(l), Some(Constant::Int(r))) => (l - r).ok().map(Constant::Int), - (BiMul, Constant::Int(l), Some(Constant::Int(r))) => (l * r).ok().map(Constant::Int), - (BiDiv, Constant::Int(l), Some(Constant::Int(r))) => (l / r).ok().map(Constant::Int), - (BiRem, Constant::Int(l), Some(Constant::Int(r))) => (l % r).ok().map(Constant::Int), - (BiAnd, Constant::Bool(false), _) => Some(Constant::Bool(false)), - (BiOr, Constant::Bool(true), _) => Some(Constant::Bool(true)), - (BiAnd, Constant::Bool(true), Some(r)) | (BiOr, Constant::Bool(false), Some(r)) => Some(r), - (BiBitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), - (BiBitXor, Constant::Int(l), Some(Constant::Int(r))) => (l ^ r).ok().map(Constant::Int), - (BiBitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), - (BiBitAnd, Constant::Int(l), Some(Constant::Int(r))) => (l & r).ok().map(Constant::Int), - (BiBitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)), - (BiBitOr, Constant::Int(l), Some(Constant::Int(r))) => (l | r).ok().map(Constant::Int), - (BiShl, Constant::Int(l), Some(Constant::Int(r))) => (l << r).ok().map(Constant::Int), - (BiShr, Constant::Int(l), Some(Constant::Int(r))) => (l >> r).ok().map(Constant::Int), - (BiEq, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l == r)), - (BiNe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l != r)), - (BiLt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l < r)), - (BiLe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l <= r)), - (BiGe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l >= r)), - (BiGt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l > r)), - _ => None, + match (l, r) { + (Constant::Int(l), Some(Constant::Int(r))) => { + match self.tables.expr_ty(left).sty { + ty::TyInt(ity) => { + let l = sext(self.tcx, l, ity); + let r = sext(self.tcx, r, ity); + let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity)); + match op.node { + BiAdd => l.checked_add(r).map(zext), + BiSub => l.checked_sub(r).map(zext), + BiMul => l.checked_mul(r).map(zext), + BiDiv if r != 0 => l.checked_div(r).map(zext), + BiRem if r != 0 => l.checked_rem(r).map(zext), + BiShr => l.checked_shr(r as u128 as u32).map(zext), + BiShl => l.checked_shl(r as u128 as u32).map(zext), + BiBitXor => Some(zext(l ^ r)), + BiBitOr => Some(zext(l | r)), + BiBitAnd => Some(zext(l & r)), + BiEq => Some(Constant::Bool(l == r)), + BiNe => Some(Constant::Bool(l != r)), + BiLt => Some(Constant::Bool(l < r)), + BiLe => Some(Constant::Bool(l <= r)), + BiGe => Some(Constant::Bool(l >= r)), + BiGt => Some(Constant::Bool(l > r)), + _ => None, + } + } + ty::TyUint(_) => { + match op.node { + BiAdd => l.checked_add(r).map(Constant::Int), + BiSub => l.checked_sub(r).map(Constant::Int), + BiMul => l.checked_mul(r).map(Constant::Int), + BiDiv => l.checked_div(r).map(Constant::Int), + BiRem => l.checked_rem(r).map(Constant::Int), + BiShr => l.checked_shr(r as u32).map(Constant::Int), + BiShl => l.checked_shl(r as u32).map(Constant::Int), + BiBitXor => Some(Constant::Int(l ^ r)), + BiBitOr => Some(Constant::Int(l | r)), + BiBitAnd => Some(Constant::Int(l & r)), + BiEq => Some(Constant::Bool(l == r)), + BiNe => Some(Constant::Bool(l != r)), + BiLt => Some(Constant::Bool(l < r)), + BiLe => Some(Constant::Bool(l <= r)), + BiGe => Some(Constant::Bool(l >= r)), + BiGt => Some(Constant::Bool(l > r)), + _ => None, + } + }, + _ => None, + } + }, + (Constant::F32(l), Some(Constant::F32(r))) => match op.node { + BiAdd => Some(Constant::F32(l + r)), + BiSub => Some(Constant::F32(l - r)), + BiMul => Some(Constant::F32(l * r)), + BiDiv => Some(Constant::F32(l / r)), + BiRem => Some(Constant::F32(l * r)), + BiEq => Some(Constant::Bool(l == r)), + BiNe => Some(Constant::Bool(l != r)), + BiLt => Some(Constant::Bool(l < r)), + BiLe => Some(Constant::Bool(l <= r)), + BiGe => Some(Constant::Bool(l >= r)), + BiGt => Some(Constant::Bool(l > r)), + _ => None, + }, + (Constant::F64(l), Some(Constant::F64(r))) => match op.node { + BiAdd => Some(Constant::F64(l + r)), + BiSub => Some(Constant::F64(l - r)), + BiMul => Some(Constant::F64(l * r)), + BiDiv => Some(Constant::F64(l / r)), + BiRem => Some(Constant::F64(l * r)), + BiEq => Some(Constant::Bool(l == r)), + BiNe => Some(Constant::Bool(l != r)), + BiLt => Some(Constant::Bool(l < r)), + BiLe => Some(Constant::Bool(l <= r)), + BiGe => Some(Constant::Bool(l >= r)), + BiGt => Some(Constant::Bool(l > r)), + _ => None, + }, + (l, r) => match (op.node, l, r) { + (BiAnd, Constant::Bool(false), _) => Some(Constant::Bool(false)), + (BiOr, Constant::Bool(true), _) => Some(Constant::Bool(true)), + (BiAnd, Constant::Bool(true), Some(r)) | (BiOr, Constant::Bool(false), Some(r)) => Some(r), + (BiBitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), + (BiBitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), + (BiBitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)), + _ => None, + }, } } } + +pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<'tcx>) -> Option { + use rustc::mir::interpret::{Value, PrimVal}; + match result.val { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => match result.ty.sty { + ty::TyBool => Some(Constant::Bool(b == 1)), + ty::TyUint(_) | ty::TyInt(_) => Some(Constant::Int(b)), + ty::TyFloat(FloatTy::F32) => Some(Constant::F32(f32::from_bits(b as u32))), + ty::TyFloat(FloatTy::F64) => Some(Constant::F64(f64::from_bits(b as u64))), + // FIXME: implement other conversion + _ => None, + }, + ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(n))) => match result.ty.sty { + ty::TyRef(_, tam) => match tam.ty.sty { + ty::TyStr => { + let alloc = tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .unwrap(); + let offset = ptr.offset as usize; + let n = n as usize; + String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned()).ok().map(Constant::Str) + }, + _ => None, + }, + _ => None, + } + // FIXME: implement other conversions + _ => None, + } +} diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index c65cf92590a..3abd42d37c9 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -2,13 +2,14 @@ //! don't fit into an `i32` use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc_const_math::*; use rustc::hir::*; use rustc::ty; -use rustc::traits::Reveal; use rustc::ty::subst::Substs; +use syntax::ast::{IntTy, UintTy}; use utils::span_lint; +use consts::{Constant, miri_to_const}; +use rustc::ty::util::IntTypeExt; +use rustc::mir::interpret::GlobalId; /// **What it does:** Checks for C-like enumerations that are /// `repr(isize/usize)` and have values that don't fit into an `i32`. @@ -43,36 +44,46 @@ impl LintPass for UnportableVariant { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { #[allow(cast_possible_truncation, cast_sign_loss)] fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { + if cx.tcx.data_layout.pointer_size.bits() != 64 { + return; + } if let ItemEnum(ref def, _) = item.node { for var in &def.variants { let variant = &var.node; if let Some(body_id) = variant.disr_expr { - let expr = &cx.tcx.hir.body(body_id).value; + let param_env = ty::ParamEnv::empty(); let did = cx.tcx.hir.body_owner_def_id(body_id); - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), did); - let bad = match cx.tcx - .at(expr.span) - .const_eval(param_env.and((did, substs))) - { - Ok(&ty::Const { - val: ConstVal::Integral(Usize(Us64(i))), - .. - }) => u64::from(i as u32) != i, - Ok(&ty::Const { - val: ConstVal::Integral(Isize(Is64(i))), - .. - }) => i64::from(i as i32) != i, - _ => false, + let instance = ty::Instance::new(did, substs); + let cid = GlobalId { + instance, + promoted: None }; - if bad { + let constant = cx.tcx.const_eval(param_env.and(cid)).ok(); + if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) { + let mut ty = cx.tcx.type_of(did); + if let ty::TyAdt(adt, _) = ty.sty { + if adt.is_enum() { + ty = adt.repr.discr_type().to_ty(cx.tcx); + } + } + match ty.sty { + ty::TyInt(IntTy::Isize) => { + let val = ((val as i128) << 64) >> 64; + if val <= i32::max_value() as i128 && val >= i32::min_value() as i128 { + continue; + } + } + ty::TyUint(UintTy::Usize) if val > u32::max_value() as u128 => {}, + _ => continue, + } span_lint( cx, ENUM_CLIKE_UNPORTABLE_VARIANT, var.span, "Clike enum variant discriminant is not portable to 32-bit targets", ); - } + }; } } } diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index dd8f029501f..a601d91a185 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ErasingOp { fn check(cx: &LateContext, e: &Expr, span: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, e) { - if v.to_u128_unchecked() == 0 { + if v == 0 { span_lint( cx, ERASING_OP, diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index e1d84a07439..717245ec0f5 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,9 +1,9 @@ use consts::{constant_simple, Constant}; use rustc::hir::*; use rustc::lint::*; -use rustc_const_math::ConstInt; use syntax::codemap::Span; -use utils::{in_macro, snippet, span_lint}; +use utils::{in_macro, snippet, span_lint, unsext, clip}; +use rustc::ty; /// **What it does:** Checks for identity operations, e.g. `x + 0`. /// @@ -58,29 +58,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { } } -fn all_ones(v: &ConstInt) -> bool { - match *v { - ConstInt::I8(i) => i == !0, - ConstInt::I16(i) => i == !0, - ConstInt::I32(i) => i == !0, - ConstInt::I64(i) => i == !0, - ConstInt::I128(i) => i == !0, - ConstInt::U8(i) => i == !0, - ConstInt::U16(i) => i == !0, - ConstInt::U32(i) => i == !0, - ConstInt::U64(i) => i == !0, - ConstInt::U128(i) => i == !0, - _ => false, - } -} - #[allow(cast_possible_wrap)] fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, e) { + let check = match cx.tables.expr_ty(e).sty { + ty::TyInt(ity) => unsext(cx.tcx, -1i128, ity), + ty::TyUint(uty) => clip(cx.tcx, !0, uty), + _ => return, + }; if match m { - 0 => v.to_u128_unchecked() == 0, - -1 => all_ones(&v), - 1 => v.to_u128_unchecked() == 1, + 0 => v == 0, + -1 => v == check, + 1 => v == 1, _ => unreachable!(), } { span_lint( diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e1b8ff2dc05..0034e28fac2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -10,6 +10,7 @@ #![feature(conservative_impl_trait)] #![feature(inclusive_range_syntax, range_contains)] #![feature(macro_vis_matcher)] +#![feature(dotdoteq_in_patterns)] #![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)] #![recursion_limit = "256"] @@ -37,7 +38,6 @@ extern crate regex_syntax; extern crate quine_mc_cluskey; -extern crate rustc_const_eval; extern crate rustc_const_math; extern crate rustc_errors; extern crate rustc_plugin; diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f476b960d88..a0f3db7b784 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -6,23 +6,19 @@ use rustc::hir::def_id; use rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt}; use rustc::lint::*; -use rustc::middle::const_val::ConstVal; use rustc::middle::region; // use rustc::middle::region::CodeExtent; use rustc::middle::expr_use_visitor::*; use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::cmt; use rustc::ty::{self, Ty}; -use rustc::ty::subst::{Subst, Substs}; -use rustc_const_eval::ConstContext; +use rustc::ty::subst::Subst; use std::collections::{HashMap, HashSet}; use std::iter::{once, Iterator}; use syntax::ast; use syntax::codemap::Span; -use utils::sugg; -use utils::const_to_u64; - -use consts::constant; +use utils::{sugg, sext}; +use consts::{constant, Constant}; use utils::{get_enclosing_block, get_parent_expr, higher, in_external_macro, is_integer_literal, is_refutable, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt, @@ -1113,27 +1109,22 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx }) = higher::range(arg) { // ...and both sides are compile-time constant integers... - let parent_item = cx.tcx.hir.get_parent(arg.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - let constcx = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables); - if let Ok(start_idx) = constcx.eval(start) { - if let Ok(end_idx) = constcx.eval(end) { + if let Some((start_idx, _)) = constant(cx, start) { + if let Some((end_idx, _)) = constant(cx, end) { // ...and the start index is greater than the end index, // this loop will never run. This is often confusing for developers // who think that this will iterate from the larger value to the // smaller value. + let ty = cx.tables.expr_ty(start); let (sup, eq) = match (start_idx, end_idx) { ( - &ty::Const { - val: ConstVal::Integral(start_idx), - .. - }, - &ty::Const { - val: ConstVal::Integral(end_idx), - .. - }, - ) => (start_idx > end_idx, start_idx == end_idx), + Constant::Int(start_idx), + Constant::Int(end_idx), + ) => (match ty.sty { + ty::TyInt(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity), + ty::TyUint(_) => start_idx > end_idx, + _ => false, + }, start_idx == end_idx), _ => (false, false), }; @@ -1220,7 +1211,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { match cx.tables.expr_ty(&args[0]).sty { // If the length is greater than 32 no traits are implemented for array and // therefore we cannot use `&`. - ty::TypeVariants::TyArray(_, size) if const_to_u64(size) > 32 => (), + ty::TypeVariants::TyArray(_, size) if size.val.to_raw_bits().expect("array size") > 32 => (), _ => lint_iter_method(cx, args, arg, method_name), }; } else { @@ -1795,7 +1786,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { fn is_iterable_array(ty: Ty) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { - ty::TyArray(_, n) => (0..=32).contains(const_to_u64(n)), + ty::TyArray(_, n) => (0..=32).contains(n.val.to_raw_bits().expect("array length")), _ => false, } } @@ -2249,4 +2240,4 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { } fn decl_without_init(&mut self, _: NodeId, _: Span) {} -} \ No newline at end of file +} diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 979f0806e52..b617f098e3e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,19 +1,15 @@ use rustc::hir::*; use rustc::lint::*; -use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; -use rustc::ty::subst::Substs; -use rustc_const_eval::ConstContext; -use rustc_const_math::ConstInt; use std::cmp::Ordering; use std::collections::Bound; use syntax::ast::LitKind; -use syntax::ast::NodeId; use syntax::codemap::Span; use utils::paths; use utils::{expr_block, in_external_macro, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty}; use utils::sugg::Sugg; +use consts::{constant, Constant}; /// **What it does:** Checks for matches with a single arm where an `if let` /// will usually suffice. @@ -343,7 +339,7 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr, arms: &'tcx [Arm]) { if arms.len() >= 2 && cx.tables.expr_ty(ex).is_integral() { - let ranges = all_ranges(cx, arms, ex.id); + let ranges = all_ranges(cx, arms); let type_ranges = type_ranges(&ranges); if !type_ranges.is_empty() { if let Some((start, end)) = overlapping(&type_ranges) { @@ -460,12 +456,7 @@ fn check_match_as_ref(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn all_ranges<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm], - id: NodeId, -) -> Vec>> { - let parent_item = cx.tcx.hir.get_parent(id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - let constcx = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables); +) -> Vec> { arms.iter() .flat_map(|arm| { if let Arm { @@ -478,25 +469,19 @@ fn all_ranges<'a, 'tcx>( } else { [].iter() }.filter_map(|pat| { - if_chain! { - if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node; - if let Ok(lhs) = constcx.eval(lhs); - if let Ok(rhs) = constcx.eval(rhs); - then { - let rhs = match *range_end { - RangeEnd::Included => Bound::Included(rhs), - RangeEnd::Excluded => Bound::Excluded(rhs), - }; - return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); - } + if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node { + let lhs = constant(cx, lhs)?.0; + let rhs = constant(cx, rhs)?.0; + let rhs = match *range_end { + RangeEnd::Included => Bound::Included(rhs), + RangeEnd::Excluded => Bound::Excluded(rhs), + }; + return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); } - if_chain! { - if let PatKind::Lit(ref value) = pat.node; - if let Ok(value) = constcx.eval(value); - then { - return Some(SpannedRange { span: pat.span, node: (value, Bound::Included(value)) }); - } + if let PatKind::Lit(ref value) = pat.node { + let value = constant(cx, value)?.0; + return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) }); } None @@ -511,46 +496,31 @@ pub struct SpannedRange { pub node: (T, Bound), } -type TypedRanges = Vec>; +type TypedRanges = Vec>; /// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway /// and other types than /// `Uint` and `Int` probably don't make sense. -fn type_ranges(ranges: &[SpannedRange<&ty::Const>]) -> TypedRanges { +fn type_ranges(ranges: &[SpannedRange]) -> TypedRanges { ranges .iter() .filter_map(|range| match range.node { ( - &ty::Const { - val: ConstVal::Integral(start), - .. - }, - Bound::Included(&ty::Const { - val: ConstVal::Integral(end), - .. - }), + Constant::Int(start), + Bound::Included(Constant::Int(end)), ) => Some(SpannedRange { span: range.span, node: (start, Bound::Included(end)), }), ( - &ty::Const { - val: ConstVal::Integral(start), - .. - }, - Bound::Excluded(&ty::Const { - val: ConstVal::Integral(end), - .. - }), + Constant::Int(start), + Bound::Excluded(Constant::Int(end)), ) => Some(SpannedRange { span: range.span, node: (start, Bound::Excluded(end)), }), ( - &ty::Const { - val: ConstVal::Integral(start), - .. - }, + Constant::Int(start), Bound::Unbounded, ) => Some(SpannedRange { span: range.span, diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 57d93b44328..0e55d0f8a3a 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -1,10 +1,7 @@ use rustc::hir; use rustc::lint::*; -use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::hir::def::Def; -use rustc::ty::subst::Substs; -use rustc_const_eval::ConstContext; use std::borrow::Cow; use std::fmt; use std::iter; @@ -16,7 +13,7 @@ use utils::{get_arg_name, get_trait_def_id, implements_trait, in_external_macro, span_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::paths; use utils::sugg; -use utils::const_to_u64; +use consts::{constant, Constant}; #[derive(Clone)] pub struct Pass; @@ -1302,7 +1299,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: Ty) -> Option true, ty::TyAdt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::TyAdt(..) => match_type(cx, ty, &paths::VEC), - ty::TyArray(_, size) => const_to_u64(size) < 32, + ty::TyArray(_, size) => size.val.to_raw_bits().expect("array length") < 32, ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) => may_slice(cx, inner), _ => false, } @@ -1754,14 +1751,7 @@ fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: & /// lint for length-1 `str`s for methods in `PATTERN_METHODS` fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, arg: &'tcx hir::Expr) { - let parent_item = cx.tcx.hir.get_parent(arg.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - if let Ok(&ty::Const { - val: ConstVal::Str(r), - .. - }) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg) - { + if let Some((Constant::Str(r), _)) = constant(cx, arg) { if r.len() == 1 { let c = r.chars().next().unwrap(); let snip = snippet(cx, expr.span, ".."); diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 04cc488d562..172de7a15a5 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -2,18 +2,14 @@ use reexport::*; use rustc::hir::*; use rustc::hir::intravisit::FnKind; use rustc::lint::*; -use rustc::middle::const_val::ConstVal; use rustc::ty; -use rustc::ty::subst::Substs; -use rustc_const_eval::ConstContext; -use rustc_const_math::ConstFloat; use syntax::codemap::{ExpnFormat, Span}; use utils::{get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty}; use utils::sugg::Sugg; -use syntax::ast::{FloatTy, LitKind, CRATE_NODE_ID}; -use consts::constant; +use syntax::ast::{LitKind, CRATE_NODE_ID}; +use consts::{constant, Constant}; /// **What it does:** Checks for function arguments and let bindings denoted as /// `ref`. @@ -457,58 +453,10 @@ fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> } 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_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - let res = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(expr); - if let Ok(&ty::Const { - val: ConstVal::Float(val), - .. - }) = res - { - use std::cmp::Ordering; - match val.ty { - FloatTy::F32 => { - let zero = ConstFloat { - ty: FloatTy::F32, - bits: u128::from(0.0_f32.to_bits()), - }; - - let infinity = ConstFloat { - ty: FloatTy::F32, - bits: u128::from(::std::f32::INFINITY.to_bits()), - }; - - let neg_infinity = ConstFloat { - ty: FloatTy::F32, - bits: u128::from(::std::f32::NEG_INFINITY.to_bits()), - }; - - val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) - || val.try_cmp(neg_infinity) == Ok(Ordering::Equal) - }, - FloatTy::F64 => { - let zero = ConstFloat { - ty: FloatTy::F64, - bits: u128::from(0.0_f64.to_bits()), - }; - - let infinity = ConstFloat { - ty: FloatTy::F64, - bits: u128::from(::std::f64::INFINITY.to_bits()), - }; - - let neg_infinity = ConstFloat { - ty: FloatTy::F64, - bits: u128::from(::std::f64::NEG_INFINITY.to_bits()), - }; - - val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) - || val.try_cmp(neg_infinity) == Ok(Ordering::Equal) - }, - } - } else { - false + match constant(cx, expr) { + Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), + Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), + _ => false, } } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 21a7542e6c7..ca9044c6e8b 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -205,7 +205,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let sugg = |db: &mut DiagnosticBuilder| { if let ty::TypeVariants::TyAdt(ref def, ..) = ty.sty { if let Some(span) = cx.tcx.hir.span_if_local(def.did) { - let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing); + let param_env = ty::ParamEnv::empty(); if param_env.can_type_implement_copy(cx.tcx, ty, span).is_ok() { db.span_help(span, "consider marking this type as Copy"); } diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index e34136face9..2ac195f555b 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -47,8 +47,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply { fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) { if_chain! { if let ExprLit(ref l) = lit.node; - if let Constant::Int(ref ci) = consts::lit_to_constant(&l.node, cx.tcx, cx.tables.expr_ty(lit)); - if let Some(val) = ci.to_u64(); + if let Constant::Int(val) = consts::lit_to_constant(&l.node, cx.tables.expr_ty(lit)); if val == 1; if cx.tables.expr_ty(exp).is_integral(); then { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 39252ceed1c..c98df6464d4 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -94,16 +94,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // Range with step_by(0). if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) { use consts::{constant, Constant}; - use rustc_const_math::ConstInt::Usize; - if let Some((Constant::Int(Usize(us)), _)) = constant(cx, &args[1]) { - if us.as_u64() == 0 { - span_lint( - cx, - ITERATOR_STEP_BY_ZERO, - expr.span, - "Iterator::step_by(0) will panic at runtime", - ); - } + if let Some((Constant::Int(0), _)) = constant(cx, &args[1]) { + span_lint( + cx, + ITERATOR_STEP_BY_ZERO, + expr.span, + "Iterator::step_by(0) will panic at runtime", + ); } } else if name == "zip" && args.len() == 2 { let iter = &args[0].node; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f2c08944f50..93ba3f0e8e7 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,15 +1,11 @@ use regex_syntax; use rustc::hir::*; use rustc::lint::*; -use rustc::ty; -use rustc::middle::const_val::ConstVal; -use rustc_const_eval::ConstContext; -use rustc::ty::subst::Substs; use std::collections::HashSet; use syntax::ast::{LitKind, NodeId, StrStyle}; use syntax::codemap::{BytePos, Span}; -use syntax::symbol::InternedString; use utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint}; +use consts::{constant, Constant}; /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct @@ -141,17 +137,11 @@ fn str_span(base: Span, c: regex_syntax::ast::Span, offset: usize) -> Span { Span::new(start, end, base.ctxt()) } -fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option { - let parent_item = cx.tcx.hir.get_parent(e.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(e) { - Ok(&ty::Const { - val: ConstVal::Str(r), - .. - }) => Some(r), +fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option { + constant(cx, e).and_then(|(c, _)| match c { + Constant::Str(s) => Some(s), _ => None, - } + }) } fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index ba79bf4407b..0e9d8bdfefd 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -5,19 +5,18 @@ use rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisito use rustc::lint::*; use rustc::ty::{self, Ty, TyCtxt, TypeckTables}; use rustc::ty::layout::LayoutOf; -use rustc::ty::subst::Substs; use rustc_typeck::hir_ty_to_ty; use std::cmp::Ordering; use std::collections::BTreeMap; use std::borrow::Cow; use syntax::ast::{FloatTy, IntTy, UintTy}; -use syntax::attr::IntType; use syntax::codemap::Span; use syntax::errors::DiagnosticBuilder; use utils::{comparisons, higher, in_constant, in_external_macro, in_macro, last_path_segment, match_def_path, match_path, multispan_sugg, opt_def_id, same_tys, snippet, snippet_opt, span_help_and_lint, span_lint, - span_lint_and_sugg, span_lint_and_then}; + span_lint_and_sugg, span_lint_and_then, clip, unsext, sext, int_bits}; use utils::paths; +use consts::{constant, Constant}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -1298,58 +1297,20 @@ fn detect_absurd_comparison<'a, 'tcx>( } fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option> { - use rustc::middle::const_val::ConstVal::*; - use rustc_const_math::*; - use rustc_const_eval::*; use types::ExtremeType::*; let ty = cx.tables.expr_ty(expr); - match ty.sty { - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) => (), - _ => return None, - }; + let cv = constant(cx, expr)?.0; - let parent_item = cx.tcx.hir.get_parent(expr.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - let cv = match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(expr) { - Ok(val) => val, - Err(_) => return None, - }; + let which = match (&ty.sty, cv) { + (&ty::TyBool, Constant::Bool(false)) | + (&ty::TyUint(_), Constant::Int(0)) => Minimum, + (&ty::TyInt(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::min_value() >> (128 - int_bits(cx.tcx, ity)), ity) => Minimum, - let which = match (&ty.sty, cv.val) { - (&ty::TyBool, Bool(false)) | - (&ty::TyInt(IntTy::Isize), Integral(Isize(Is32(::std::i32::MIN)))) | - (&ty::TyInt(IntTy::Isize), Integral(Isize(Is64(::std::i64::MIN)))) | - (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) | - (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) | - (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) | - (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) | - (&ty::TyInt(IntTy::I128), Integral(I128(::std::i128::MIN))) | - (&ty::TyUint(UintTy::Usize), Integral(Usize(Us32(::std::u32::MIN)))) | - (&ty::TyUint(UintTy::Usize), Integral(Usize(Us64(::std::u64::MIN)))) | - (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) | - (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MIN))) | - (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MIN))) | - (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) | - (&ty::TyUint(UintTy::U128), Integral(U128(::std::u128::MIN))) => Minimum, - - (&ty::TyBool, Bool(true)) | - (&ty::TyInt(IntTy::Isize), Integral(Isize(Is32(::std::i32::MAX)))) | - (&ty::TyInt(IntTy::Isize), Integral(Isize(Is64(::std::i64::MAX)))) | - (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) | - (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) | - (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) | - (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) | - (&ty::TyInt(IntTy::I128), Integral(I128(::std::i128::MAX))) | - (&ty::TyUint(UintTy::Usize), Integral(Usize(Us32(::std::u32::MAX)))) | - (&ty::TyUint(UintTy::Usize), Integral(Usize(Us64(::std::u64::MAX)))) | - (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) | - (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MAX))) | - (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MAX))) | - (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MAX))) | - (&ty::TyUint(UintTy::U128), Integral(U128(::std::u128::MAX))) => Maximum, + (&ty::TyBool, Constant::Bool(true)) => Maximum, + (&ty::TyInt(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::max_value() >> (128 - int_bits(cx.tcx, ity)), ity) => Maximum, + (&ty::TyUint(uty), Constant::Int(i)) if clip(cx.tcx, u128::max_value(), uty) == i => Maximum, _ => return None, }; @@ -1524,24 +1485,16 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( } } -#[allow(cast_possible_wrap)] fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option { - use rustc::middle::const_val::ConstVal::*; - use rustc_const_eval::ConstContext; - - let parent_item = cx.tcx.hir.get_parent(expr.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(expr) { - Ok(val) => if let Integral(const_int) = val.val { - match const_int.int_type() { - IntType::SignedInt(_) => Some(FullInt::S(const_int.to_u128_unchecked() as i128)), - IntType::UnsignedInt(_) => Some(FullInt::U(const_int.to_u128_unchecked())), - } - } else { - None - }, - Err(_) => None, + let val = constant(cx, expr)?.0; + if let Constant::Int(const_int) = val { + match cx.tables.expr_ty(expr).sty { + ty::TyInt(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), + ty::TyUint(_) => Some(FullInt::U(const_int)), + _ => None, + } + } else { + None } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 2f2f0c04054..b171bdf4030 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -8,7 +8,7 @@ use rustc::hir::map::Node; use rustc::lint::{LateContext, Level, Lint, LintContext}; use rustc::session::Session; use rustc::traits; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, layout}; use rustc_errors; use std::borrow::Cow; use std::env; @@ -276,14 +276,6 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option { } } -pub fn const_to_u64(c: &ty::Const) -> u64 { - c.val - .to_const_int() - .expect("eddyb says this works") - .to_u64() - .expect("see previous expect") -} - /// Convenience function to get the `DefId` of a trait by path. pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option { let def = match path_to_def(cx, path) { @@ -1071,3 +1063,26 @@ pub fn get_arg_name(pat: &Pat) -> Option { _ => None, } } + +pub fn int_bits(tcx: TyCtxt, ity: ast::IntTy) -> u64 { + layout::Integer::from_attr(tcx, attr::IntType::SignedInt(ity)).size().bits() +} + +/// Turn a constant int byte representation into an i128 +pub fn sext(tcx: TyCtxt, u: u128, ity: ast::IntTy) -> i128 { + let amt = 128 - int_bits(tcx, ity); + ((u as i128) << amt) >> amt +} + +/// clip unused bytes +pub fn unsext(tcx: TyCtxt, u: i128, ity: ast::IntTy) -> u128 { + let amt = 128 - int_bits(tcx, ity); + ((u as u128) << amt) >> amt +} + +/// clip unused bytes +pub fn clip(tcx: TyCtxt, u: u128, ity: ast::UintTy) -> u128 { + let bits = layout::Integer::from_attr(tcx, attr::IntType::UnsignedInt(ity)).size().bits(); + let amt = 128 - bits; + (u << amt) >> amt +} diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index e1c226466f9..4762c730683 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,10 +1,9 @@ use rustc::hir::*; use rustc::lint::*; use rustc::ty::{self, Ty}; -use rustc::ty::subst::Substs; -use rustc_const_eval::ConstContext; use syntax::codemap::Span; use utils::{higher, is_copy, snippet, span_lint_and_sugg}; +use consts::constant; /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would /// be possible. @@ -67,13 +66,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) { let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { - let parent_item = cx.tcx.hir.get_parent(len.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - if ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables) - .eval(len) - .is_ok() - { + if constant(cx, len).is_some() { format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")) } else { return; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index efe23bcdc47..416ee155174 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,4 +1,4 @@ -use consts::{constant_simple, Constant, FloatWidth}; +use consts::{constant_simple, Constant}; use rustc::lint::*; use rustc::hir::*; use utils::span_help_and_lint; @@ -37,16 +37,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. - if let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(cx, left); - if let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(cx, right); - if Ok(0.0) == lhs_value.parse(); - if Ok(0.0) == rhs_value.parse(); + if let Some(lhs_value) = constant_simple(cx, left); + if let Some(rhs_value) = constant_simple(cx, right); + if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value; + if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value; then { // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, // match the precision of the literals that are given. - let float_type = match (lhs_width, rhs_width) { - (FloatWidth::F64, _) - | (_, FloatWidth::F64) => "f64", + let float_type = match (lhs_value, rhs_value) { + (Constant::F64(_), _) + | (_, Constant::F64(_)) => "f64", _ => "f32" }; span_help_and_lint( diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin-type-shadow.stderr index 85595fb0233..5757a6ef390 100644 --- a/tests/ui/builtin-type-shadow.stderr +++ b/tests/ui/builtin-type-shadow.stderr @@ -19,4 +19,4 @@ error[E0308]: mismatched types error: aborting due to 2 previous errors -If you want more information on this error, try using "rustc --explain E0308" +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/conf_bad_arg.stderr b/tests/ui/conf_bad_arg.stderr index 30a87e23275..094b7d49cb5 100644 --- a/tests/ui/conf_bad_arg.stderr +++ b/tests/ui/conf_bad_arg.stderr @@ -8,4 +8,4 @@ error[E0658]: compiler plugins are experimental and possibly buggy (see issue #2 error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0658" +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_bad_toml.stderr b/tests/ui/conf_bad_toml.stderr index f01b5605a51..640b1c5e610 100644 --- a/tests/ui/conf_bad_toml.stderr +++ b/tests/ui/conf_bad_toml.stderr @@ -8,4 +8,4 @@ error[E0658]: compiler plugins are experimental and possibly buggy (see issue #2 error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0658" +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_bad_type.stderr b/tests/ui/conf_bad_type.stderr index ea9cf0acdd8..f92b52ec032 100644 --- a/tests/ui/conf_bad_type.stderr +++ b/tests/ui/conf_bad_type.stderr @@ -8,4 +8,4 @@ error[E0658]: compiler plugins are experimental and possibly buggy (see issue #2 error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0658" +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_french_blacklisted_name.stderr b/tests/ui/conf_french_blacklisted_name.stderr index d09ae43301c..214226ac2f9 100644 --- a/tests/ui/conf_french_blacklisted_name.stderr +++ b/tests/ui/conf_french_blacklisted_name.stderr @@ -8,4 +8,4 @@ error[E0658]: compiler plugins are experimental and possibly buggy (see issue #2 error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0658" +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_path_non_string.stderr b/tests/ui/conf_path_non_string.stderr index 6af3b595921..10b007b0de0 100644 --- a/tests/ui/conf_path_non_string.stderr +++ b/tests/ui/conf_path_non_string.stderr @@ -8,4 +8,4 @@ error[E0658]: compiler plugins are experimental and possibly buggy (see issue #2 error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0658" +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_unknown_key.stderr b/tests/ui/conf_unknown_key.stderr index 80a60bd8f2e..d7ac055c517 100644 --- a/tests/ui/conf_unknown_key.stderr +++ b/tests/ui/conf_unknown_key.stderr @@ -8,4 +8,4 @@ error[E0658]: compiler plugins are experimental and possibly buggy (see issue #2 error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0658" +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index a764403d039..df404a1eec3 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -1,70 +1,10 @@ -error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:43:5 - | -43 | ONE == 1f32; - | ^^^^^^^^^^^ help: consider comparing them within some error: `(ONE - 1f32).abs() < error` - | - = note: `-D float-cmp` implied by `-D warnings` -note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:43:5 - | -43 | ONE == 1f32; - | ^^^^^^^^^^^ - -error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:44:5 - | -44 | ONE == 1.0 + 0.0; - | ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE - (1.0 + 0.0)).abs() < error` - | -note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:44:5 - | -44 | ONE == 1.0 + 0.0; - | ^^^^^^^^^^^^^^^^ - -error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:45:5 - | -45 | ONE + ONE == ZERO + ONE + ONE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - (ZERO + ONE + ONE)).abs() < error` - | -note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:45:5 - | -45 | ONE + ONE == ZERO + ONE + ONE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:46:5 - | -46 | ONE != 2.0; - | ^^^^^^^^^^ help: consider comparing them within some error: `(ONE - 2.0).abs() < error` - | -note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:46:5 - | -46 | ONE != 2.0; - | ^^^^^^^^^^ - -error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:48:5 - | -48 | twice(ONE) != ONE; - | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(ONE) - ONE).abs() < error` - | -note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:48:5 - | -48 | twice(ONE) != ONE; - | ^^^^^^^^^^^^^^^^^ - error: strict comparison of f32 or f64 --> $DIR/float_cmp.rs:49:5 | 49 | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() < error` | + = note: `-D float-cmp` implied by `-D warnings` note: std::f32::EPSILON and std::f64::EPSILON are available. --> $DIR/float_cmp.rs:49:5 | @@ -95,5 +35,5 @@ note: std::f32::EPSILON and std::f64::EPSILON are available. 57 | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/op_ref.stderr b/tests/ui/op_ref.stderr index a4f7b3c6761..28223563db1 100644 --- a/tests/ui/op_ref.stderr +++ b/tests/ui/op_ref.stderr @@ -10,5 +10,13 @@ help: use the values directly 13 | let foo = 5 - 6; | -error: aborting due to previous error +error: taken reference of right operand + --> $DIR/op_ref.rs:21:8 + | +21 | if b < &a { + | ^^^^-- + | | + | help: use the right value directly: `a` + +error: aborting due to 2 previous errors diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index b81e59c07f1..bc2a70beffd 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -13,7 +13,7 @@ error: constant division of 0.0 with 0.0 will always result in NaN | ^^^^^^^^^ | = note: `-D zero-divided-by-zero` implied by `-D warnings` - = help: Consider using `std::f32::NAN` if you would like a constant representing NaN + = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:8:19