Merge pull request #1584 from ensch/master

Fix for rustc 1.17.0-nightly (be760566c 2017-02-28)
This commit is contained in:
Oliver Schneider 2017-03-02 12:26:23 +01:00 committed by GitHub
commit 3ebc12d25f
29 changed files with 394 additions and 311 deletions

View file

@ -1,9 +1,8 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty; use rustc::ty;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use rustc_const_math::ConstInt; use rustc_const_math::{ConstUsize,ConstIsize,ConstInt};
use rustc::hir; use rustc::hir;
use syntax::ast::RangeLimits; use syntax::ast::RangeLimits;
use utils::{self, higher}; use utils::{self, higher};
@ -61,11 +60,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing {
// Array with known size can be checked statically // Array with known size can be checked statically
let ty = cx.tables.expr_ty(array); let ty = cx.tables.expr_ty(array);
if let ty::TyArray(_, size) = ty.sty { if let ty::TyArray(_, size) = ty.sty {
let size = ConstInt::Infer(size as u128); let size = ConstInt::Usize(ConstUsize::new(size as u64, cx.sess().target.uint_type).expect("array size is invalid"));
let constcx = ConstContext::with_tables(cx.tcx, cx.tables); let constcx = ConstContext::with_tables(cx.tcx, cx.tables);
// Index is a constant uint // Index is a constant uint
let const_index = constcx.eval(index, ExprTypeChecked); let const_index = constcx.eval(index);
if let Ok(ConstVal::Integral(const_index)) = const_index { if let Ok(ConstVal::Integral(const_index)) = const_index {
if size <= const_index { if size <= const_index {
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds");
@ -77,10 +76,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing {
// Index is a constant range // Index is a constant range
if let Some(range) = higher::range(index) { if let Some(range) = higher::range(index) {
let start = range.start let start = range.start
.map(|start| constcx.eval(start, ExprTypeChecked)) .map(|start| constcx.eval(start))
.map(|v| v.ok()); .map(|v| v.ok());
let end = range.end let end = range.end
.map(|end| constcx.eval(end, ExprTypeChecked)) .map(|end| constcx.eval(end))
.map(|v| v.ok()); .map(|v| v.ok());
if let Some((start, end)) = to_const_range(&start, &end, range.limits, size) { if let Some((start, end)) = to_const_range(&start, &end, range.limits, size) {
@ -117,13 +116,30 @@ fn to_const_range(
let start = match *start { let start = match *start {
Some(Some(ConstVal::Integral(x))) => x, Some(Some(ConstVal::Integral(x))) => x,
Some(_) => return None, Some(_) => return None,
None => ConstInt::Infer(0), None => ConstInt::U8(0),
}; };
let end = match *end { let end = match *end {
Some(Some(ConstVal::Integral(x))) => { Some(Some(ConstVal::Integral(x))) => {
if limits == RangeLimits::Closed { if limits == RangeLimits::Closed {
(x + ConstInt::Infer(1)).expect("such a big array is not realistic") 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")
} else { } else {
x x
} }

View file

@ -237,6 +237,7 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str
} }
fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u128> { fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u128> {
use rustc::ty::subst::Substs;
match lit.node { match lit.node {
ExprLit(ref lit_ptr) => { ExprLit(ref lit_ptr) => {
if let LitKind::Int(value, _) = lit_ptr.node { if let LitKind::Int(value, _) = lit_ptr.node {
@ -248,7 +249,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u128> {
ExprPath(ref qpath) => { ExprPath(ref qpath) => {
let def = cx.tables.qpath_def(qpath, lit.id); let def = cx.tables.qpath_def(qpath, lit.id);
if let Def::Const(def_id) = def { if let Def::Const(def_id) = def {
lookup_const_by_id(cx.tcx, def_id, None).and_then(|(l, _tab, _ty)| fetch_int_literal(cx, l)) lookup_const_by_id(cx.tcx, def_id, Substs::empty()).and_then(|(l, _ty)| fetch_int_literal(cx, l))
} else { } else {
None None
} }

View file

@ -3,14 +3,15 @@
use rustc::lint::LateContext; use rustc::lint::LateContext;
use rustc::hir::def::Def; use rustc::hir::def::Def;
use rustc_const_eval::lookup_const_by_id; use rustc_const_eval::lookup_const_by_id;
use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc_const_math::ConstInt;
use rustc::hir::*; use rustc::hir::*;
use rustc::ty::{TyCtxt, self};
use std::cmp::Ordering::{self, Equal}; use std::cmp::Ordering::{self, Equal};
use std::cmp::PartialOrd; use std::cmp::PartialOrd;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy, NodeId}; use syntax::ast::{FloatTy, LitKind, StrStyle, NodeId};
use syntax::ptr::P; use syntax::ptr::P;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -174,29 +175,36 @@ impl PartialOrd for Constant {
/// parse a `LitKind` to a `Constant` /// parse a `LitKind` to a `Constant`
#[allow(cast_possible_wrap)] #[allow(cast_possible_wrap)]
pub fn lit_to_constant(lit: &LitKind) -> Constant { pub fn lit_to_constant<'a, 'tcx>(lit: &LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, mut ty: 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 { match *lit {
LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style),
LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)),
LitKind::ByteStr(ref s) => Constant::Binary(s.clone()), LitKind::ByteStr(ref s) => Constant::Binary(s.clone()),
LitKind::Char(c) => Constant::Char(c), LitKind::Char(c) => Constant::Char(c),
LitKind::Int(value, LitIntType::Unsuffixed) => Constant::Int(ConstInt::Infer(value)), LitKind::Int(n, hint) => {
LitKind::Int(value, LitIntType::Unsigned(UintTy::U8)) => Constant::Int(ConstInt::U8(value as u8)), match (&ty.sty, hint) {
LitKind::Int(value, LitIntType::Unsigned(UintTy::U16)) => Constant::Int(ConstInt::U16(value as u16)), (&ty::TyInt(ity), _) |
LitKind::Int(value, LitIntType::Unsigned(UintTy::U32)) => Constant::Int(ConstInt::U32(value as u32)), (_, Signed(ity)) => {
LitKind::Int(value, LitIntType::Unsigned(UintTy::U64)) => Constant::Int(ConstInt::U64(value as u64)), Constant::Int(ConstInt::new_signed_truncating(n as i128,
LitKind::Int(value, LitIntType::Unsigned(UintTy::U128)) => Constant::Int(ConstInt::U128(value as u128)), ity, tcx.sess.target.int_type))
LitKind::Int(value, LitIntType::Unsigned(UintTy::Us)) => { }
Constant::Int(ConstInt::Usize(ConstUsize::Us32(value as u32))) (&ty::TyUint(uty), _) |
}, (_, Unsigned(uty)) => {
LitKind::Int(value, LitIntType::Signed(IntTy::I8)) => Constant::Int(ConstInt::I8(value as i8)), Constant::Int(ConstInt::new_unsigned_truncating(n as u128,
LitKind::Int(value, LitIntType::Signed(IntTy::I16)) => Constant::Int(ConstInt::I16(value as i16)), uty, tcx.sess.target.uint_type))
LitKind::Int(value, LitIntType::Signed(IntTy::I32)) => Constant::Int(ConstInt::I32(value as i32)), }
LitKind::Int(value, LitIntType::Signed(IntTy::I64)) => Constant::Int(ConstInt::I64(value as i64)), _ => bug!()
LitKind::Int(value, LitIntType::Signed(IntTy::I128)) => Constant::Int(ConstInt::I128(value as i128)), }
LitKind::Int(value, LitIntType::Signed(IntTy::Is)) => { }
Constant::Int(ConstInt::Isize(ConstIsize::Is32(value as i32)))
},
LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()),
LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any), LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any),
LitKind::Bool(b) => Constant::Bool(b), LitKind::Bool(b) => Constant::Bool(b),
@ -231,22 +239,20 @@ fn neg_float_str(s: &str) -> String {
pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> {
let mut cx = ConstEvalLateContext { let mut cx = ConstEvalLateContext {
lcx: Some(lcx), tcx: lcx.tcx,
tables: lcx.tables,
needed_resolution: false, needed_resolution: false,
}; };
cx.expr(e).map(|cst| (cst, cx.needed_resolution)) cx.expr(e).map(|cst| (cst, cx.needed_resolution))
} }
pub fn constant_simple(e: &Expr) -> Option<Constant> { pub fn constant_simple(lcx: &LateContext, e: &Expr) -> Option<Constant> {
let mut cx = ConstEvalLateContext { constant(lcx, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
lcx: None,
needed_resolution: false,
};
cx.expr(e)
} }
struct ConstEvalLateContext<'c, 'cc: 'c> { struct ConstEvalLateContext<'a, 'tcx: 'a> {
lcx: Option<&'c LateContext<'c, 'cc>>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
needed_resolution: bool, needed_resolution: bool,
} }
@ -257,17 +263,14 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
ExprPath(ref qpath) => self.fetch_path(qpath, e.id), ExprPath(ref qpath) => self.fetch_path(qpath, e.id),
ExprBlock(ref block) => self.block(block), ExprBlock(ref block) => self.block(block),
ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise), ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise),
ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), ExprLit(ref lit) => Some(lit_to_constant(&lit.node, self.tcx, self.tables.expr_ty(e))),
ExprArray(ref vec) => self.multi(vec).map(Constant::Vec), ExprArray(ref vec) => self.multi(vec).map(Constant::Vec),
ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple),
ExprRepeat(ref value, number_id) => { ExprRepeat(ref value, number_id) => {
if let Some(lcx) = self.lcx { let val = &self.tcx.hir.body(number_id).value;
self.binop_apply(value, self.binop_apply(value,
&lcx.tcx.hir.body(number_id).value, val,
|v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize))) |v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize)))
} else {
None
}
}, },
ExprUnary(op, ref operand) => { ExprUnary(op, ref operand) => {
self.expr(operand).and_then(|o| match op { self.expr(operand).and_then(|o| match op {
@ -292,16 +295,20 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
/// lookup a possibly constant expression from a ExprPath /// lookup a possibly constant expression from a ExprPath
fn fetch_path(&mut self, qpath: &QPath, id: NodeId) -> Option<Constant> { fn fetch_path(&mut self, qpath: &QPath, id: NodeId) -> Option<Constant> {
if let Some(lcx) = self.lcx { let def = self.tables.qpath_def(qpath, id);
let def = lcx.tables.qpath_def(qpath, id);
match def { match def {
Def::Const(def_id) | Def::Const(def_id) |
Def::AssociatedConst(def_id) => { Def::AssociatedConst(def_id) => {
let substs = Some(lcx.tables let substs = self.tables
.node_id_item_substs(id) .node_id_item_substs(id)
.unwrap_or_else(|| lcx.tcx.intern_substs(&[]))); .unwrap_or_else(|| self.tcx.intern_substs(&[]));
if let Some((const_expr, _tab, _ty)) = lookup_const_by_id(lcx.tcx, def_id, substs) { if let Some((const_expr, tables)) = lookup_const_by_id(self.tcx, def_id, substs) {
let ret = self.expr(const_expr); let mut cx = ConstEvalLateContext {
tcx: self.tcx,
tables,
needed_resolution: false,
};
let ret = cx.expr(const_expr);
if ret.is_some() { if ret.is_some() {
self.needed_resolution = true; self.needed_resolution = true;
} }
@ -310,7 +317,6 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}, },
_ => {}, _ => {},
} }
}
None None
} }

View file

@ -136,7 +136,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
let ty = self.cx.tables.node_id_to_type(callee.id); let ty = self.cx.tables.node_id_to_type(callee.id);
match ty.sty { match ty.sty {
ty::TyFnDef(_, _, ty) | ty::TyFnDef(_, _, ty) |
ty::TyFnPtr(ty) if ty.sig.skip_binder().output().sty == ty::TyNever => { ty::TyFnPtr(ty) if ty.skip_binder().output().sty == ty::TyNever => {
self.divergence += 1; self.divergence += 1;
}, },
_ => (), _ => (),

View file

@ -45,7 +45,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
if let Some(body_id) = variant.disr_expr { if let Some(body_id) = variant.disr_expr {
use rustc_const_eval::*; use rustc_const_eval::*;
let constcx = ConstContext::new(cx.tcx, body_id); let constcx = ConstContext::new(cx.tcx, body_id);
let bad = match constcx.eval(&cx.tcx.hir.body(body_id).value, EvalHint::ExprTypeChecked) { let bad = match constcx.eval(&cx.tcx.hir.body(body_id).value) {
Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i, Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i,
Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i, Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i,
_ => false, _ => false,

View file

@ -66,7 +66,7 @@ fn check_closure(cx: &LateContext, expr: &Expr) {
// Is it an unsafe function? They don't implement the closure traits // Is it an unsafe function? They don't implement the closure traits
ty::TyFnDef(_, _, fn_ty) | ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => { ty::TyFnPtr(fn_ty) => {
if fn_ty.unsafety == Unsafety::Unsafe || fn_ty.sig.skip_binder().output().sty == ty::TyNever { if fn_ty.skip_binder().unsafety == Unsafety::Unsafe || fn_ty.skip_binder().output().sty == ty::TyNever {
return; return;
} }
}, },

View file

@ -129,7 +129,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
match self.cx.tables.expr_ty(func).sty { match self.cx.tables.expr_ty(func).sty {
ty::TyFnDef(_, _, fn_ty) | ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => { ty::TyFnPtr(fn_ty) => {
if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&fn_ty.sig).output().sty { if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&fn_ty).output().sty {
self.report_diverging_sub_expr(e); self.report_diverging_sub_expr(e);
} }
}, },

View file

@ -3,7 +3,7 @@ use rustc::lint::*;
use rustc::hir::*; use rustc::hir::*;
use syntax::codemap::Span; use syntax::codemap::Span;
use utils::{span_lint, snippet, in_macro}; use utils::{span_lint, snippet, in_macro};
use rustc_const_math::ConstInt; use syntax::attr::IntType::{SignedInt, UnsignedInt};
/// **What it does:** Checks for identity operations, e.g. `x + 0`. /// **What it does:** Checks for identity operations, e.g. `x + 0`.
/// ///
@ -60,11 +60,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp {
fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) {
if let Some(v @ Constant::Int(_)) = constant_simple(e) { if let Some(Constant::Int(v)) = constant_simple(cx, e) {
if match m { if match m {
0 => v == Constant::Int(ConstInt::Infer(0)), 0 => v.to_u128_unchecked() == 0,
-1 => v == Constant::Int(ConstInt::InferSigned(-1)), -1 => match v.int_type() {
1 => v == Constant::Int(ConstInt::Infer(1)), SignedInt(_) => #[allow(cast_possible_wrap)] (v.to_u128_unchecked() as i128 == -1),
UnsignedInt(_) => false
},
1 => v.to_u128_unchecked() == 1,
_ => unreachable!(), _ => unreachable!(),
} { } {
span_lint(cx, span_lint(cx,

View file

@ -2,10 +2,8 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::hir::*; use rustc::hir::*;
use utils::{span_lint_and_then, snippet_opt}; use utils::{span_lint_and_then, snippet_opt, type_size};
use rustc::ty::layout::TargetDataLayout;
use rustc::ty::TypeFoldable; use rustc::ty::TypeFoldable;
use rustc::traits::Reveal;
/// **What it does:** Checks for large size differences between variants on `enum`s. /// **What it does:** Checks for large size differences between variants on `enum`s.
/// ///
@ -55,8 +53,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
let mut largest_variant: Option<(_, _)> = None; let mut largest_variant: Option<(_, _)> = None;
for (i, variant) in adt.variants.iter().enumerate() { for (i, variant) in adt.variants.iter().enumerate() {
let data_layout = TargetDataLayout::parse(cx.sess());
cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
let size: u64 = variant.fields let size: u64 = variant.fields
.iter() .iter()
.map(|f| { .map(|f| {
@ -64,10 +60,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
if ty.needs_subst() { if ty.needs_subst() {
0 // we can't reason about generics, so we treat them as zero sized 0 // we can't reason about generics, so we treat them as zero sized
} else { } else {
ty.layout(&infcx) type_size(cx, ty).expect("size should be computable for concrete type")
.expect("layout should be computable for concrete type")
.size(&data_layout)
.bytes()
} }
}) })
.sum(); .sum();
@ -76,7 +69,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
update_if(&mut smallest_variant, grouped, |a, b| b.0 <= a.0); update_if(&mut smallest_variant, grouped, |a, b| b.0 <= a.0);
update_if(&mut largest_variant, grouped, |a, b| b.0 >= a.0); update_if(&mut largest_variant, grouped, |a, b| b.0 >= a.0);
});
} }
if let (Some(smallest), Some(largest)) = (smallest_variant, largest_variant) { if let (Some(smallest), Some(largest)) = (smallest_variant, largest_variant) {

View file

@ -186,7 +186,8 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
fn is_is_empty(cx: &LateContext, item: &ty::AssociatedItem) -> bool { fn is_is_empty(cx: &LateContext, item: &ty::AssociatedItem) -> bool {
if let ty::AssociatedKind::Method = item.kind { if let ty::AssociatedKind::Method = item.kind {
if &*item.name.as_str() == "is_empty" { if &*item.name.as_str() == "is_empty" {
let ty = cx.tcx.item_type(item.def_id).fn_sig().skip_binder(); let sig = cx.tcx.item_type(item.def_id).fn_sig();
let ty = sig.skip_binder();
ty.inputs().len() == 1 ty.inputs().len() == 1
} else { } else {
false false
@ -198,7 +199,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
/// Check the inherent impl's items for an `is_empty(self)` method. /// Check the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext, id: DefId) -> bool { fn has_is_empty_impl(cx: &LateContext, id: DefId) -> bool {
cx.tcx.inherent_impls.borrow().get(&id).map_or(false, |impls| { cx.tcx.maps.inherent_impls.borrow().get(&id).map_or(false, |impls| {
impls.iter().any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item))) impls.iter().any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
}) })
} }

View file

@ -257,7 +257,7 @@ impl<'v, 't> RefVisitor<'v, 't> {
} }
}, },
Def::Trait(def_id) => { Def::Trait(def_id) => {
let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; let trait_def = self.cx.tcx.maps.trait_def.borrow()[&def_id];
for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions { for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions {
self.record(&None); self.record(&None);
} }

View file

@ -8,7 +8,6 @@ use rustc::lint::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::middle::region::CodeExtent; use rustc::middle::region::CodeExtent;
use rustc::ty; use rustc::ty;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use std::collections::HashMap; use std::collections::HashMap;
use syntax::ast; use syntax::ast;
@ -596,8 +595,8 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) {
// ...and both sides are compile-time constant integers... // ...and both sides are compile-time constant integers...
let constcx = ConstContext::with_tables(cx.tcx, cx.tables); let constcx = ConstContext::with_tables(cx.tcx, cx.tables);
if let Ok(start_idx) = constcx.eval(start, ExprTypeChecked) { if let Ok(start_idx) = constcx.eval(start) {
if let Ok(end_idx) = constcx.eval(end, ExprTypeChecked) { if let Ok(end_idx) = constcx.eval(end) {
// ...and the start index is greater than the end index, // ...and the start index is greater than the end index,
// this loop will never run. This is often confusing for developers // this loop will never run. This is often confusing for developers
// who think that this will iterate from the larger value to the // who think that this will iterate from the larger value to the

View file

@ -2,7 +2,6 @@ use rustc::hir::*;
use rustc::lint::*; use rustc::lint::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty; use rustc::ty;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use rustc_const_math::ConstInt; use rustc_const_math::ConstInt;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -415,7 +414,7 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match
} }
/// Get all arms that are unbounded `PatRange`s. /// Get all arms that are unbounded `PatRange`s.
fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &[Arm]) -> Vec<SpannedRange<ConstVal<'tcx>>> {
let constcx = ConstContext::with_tables(cx.tcx, cx.tables); let constcx = ConstContext::with_tables(cx.tcx, cx.tables);
arms.iter() arms.iter()
.flat_map(|arm| { .flat_map(|arm| {
@ -427,8 +426,8 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> {
.filter_map(|pat| { .filter_map(|pat| {
if_let_chain! {[ if_let_chain! {[
let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node, let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node,
let Ok(lhs) = constcx.eval(lhs, ExprTypeChecked), let Ok(lhs) = constcx.eval(lhs),
let Ok(rhs) = constcx.eval(rhs, ExprTypeChecked) let Ok(rhs) = constcx.eval(rhs)
], { ], {
let rhs = match *range_end { let rhs = match *range_end {
RangeEnd::Included => Bound::Included(rhs), RangeEnd::Included => Bound::Included(rhs),
@ -439,7 +438,7 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> {
if_let_chain! {[ if_let_chain! {[
let PatKind::Lit(ref value) = pat.node, let PatKind::Lit(ref value) = pat.node,
let Ok(value) = constcx.eval(value, ExprTypeChecked) let Ok(value) = constcx.eval(value)
], { ], {
return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) }); return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) });
}} }}

View file

@ -36,7 +36,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget {
let forgot_ty = cx.tables.expr_ty(&args[0]); let forgot_ty = cx.tables.expr_ty(&args[0]);
if match forgot_ty.ty_adt_def() { if match forgot_ty.ty_adt_def() {
Some(def) => def.has_dtor(), Some(def) => def.has_dtor(cx.tcx),
_ => false, _ => false,
} { } {
span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type");

View file

@ -3,7 +3,6 @@ use rustc::lint::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty; use rustc::ty;
use rustc::hir::def::Def; use rustc::hir::def::Def;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
@ -1240,7 +1239,7 @@ fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other:
/// lint for length-1 `str`s for methods in `PATTERN_METHODS` /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) {
if let Ok(ConstVal::Str(r)) = ConstContext::with_tables(cx.tcx, cx.tables).eval(arg, ExprTypeChecked) { if let Ok(ConstVal::Str(r)) = ConstContext::with_tables(cx.tcx, cx.tables).eval(arg) {
if r.len() == 1 { if r.len() == 1 {
let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r));
span_lint_and_then(cx, span_lint_and_then(cx,

View file

@ -65,9 +65,9 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &'
let def_id = cx.tables.qpath_def(qpath, path.id).def_id(); let def_id = cx.tables.qpath_def(qpath, path.id).def_id();
if match_def_path(cx.tcx, def_id, &paths::CMP_MIN) { if match_def_path(cx.tcx, def_id, &paths::CMP_MIN) {
fetch_const(args, MinMax::Min) fetch_const(cx, args, MinMax::Min)
} else if match_def_path(cx.tcx, def_id, &paths::CMP_MAX) { } else if match_def_path(cx.tcx, def_id, &paths::CMP_MAX) {
fetch_const(args, MinMax::Max) fetch_const(cx, args, MinMax::Max)
} else { } else {
None None
} }
@ -79,18 +79,18 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &'
} }
} }
fn fetch_const(args: &[Expr], m: MinMax) -> Option<(MinMax, Constant, &Expr)> { fn fetch_const<'a>(cx: &LateContext, args: &'a [Expr], m: MinMax) -> Option<(MinMax, Constant, &'a Expr)> {
if args.len() != 2 { if args.len() != 2 {
return None; return None;
} }
if let Some(c) = constant_simple(&args[0]) { if let Some(c) = constant_simple(cx, &args[0]) {
if constant_simple(&args[1]).is_none() { if constant_simple(cx, &args[1]).is_none() {
// otherwise ignore // otherwise ignore
Some((m, c, &args[1])) Some((m, c, &args[1]))
} else { } else {
None None
} }
} else if let Some(c) = constant_simple(&args[1]) { } else if let Some(c) = constant_simple(cx, &args[1]) {
Some((m, c, &args[0])) Some((m, c, &args[0]))
} else { } else {
None None

View file

@ -4,7 +4,6 @@ use rustc::hir::intravisit::FnKind;
use rustc::lint::*; use rustc::lint::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty; use rustc::ty;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use rustc_const_math::ConstFloat; use rustc_const_math::ConstFloat;
use syntax::codemap::{Span, Spanned, ExpnFormat}; use syntax::codemap::{Span, Spanned, ExpnFormat};
@ -360,27 +359,31 @@ fn check_nan(cx: &LateContext, path: &Path, span: Span) {
} }
fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { fn is_allowed(cx: &LateContext, expr: &Expr) -> bool {
let res = ConstContext::with_tables(cx.tcx, cx.tables).eval(expr, ExprTypeChecked); let res = ConstContext::with_tables(cx.tcx, cx.tables).eval(expr);
if let Ok(ConstVal::Float(val)) = res { if let Ok(ConstVal::Float(val)) = res {
use std::cmp::Ordering; use std::cmp::Ordering;
match val {
val @ ConstFloat::F32(_) => {
let zero = ConstFloat::F32(0.0);
let zero = ConstFloat::FInfer { let infinity = ConstFloat::F32(::std::f32::INFINITY);
f32: 0.0,
f64: 0.0,
};
let infinity = ConstFloat::FInfer { let neg_infinity = ConstFloat::F32(::std::f32::NEG_INFINITY);
f32: ::std::f32::INFINITY,
f64: ::std::f64::INFINITY,
};
let neg_infinity = ConstFloat::FInfer {
f32: ::std::f32::NEG_INFINITY,
f64: ::std::f64::NEG_INFINITY,
};
val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) || val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) ||
val.try_cmp(neg_infinity) == Ok(Ordering::Equal) val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
},
val @ ConstFloat::F64(_) => {
let zero = ConstFloat::F64(0.0);
let infinity = ConstFloat::F64(::std::f64::INFINITY);
let neg_infinity = ConstFloat::F64(::std::f64::NEG_INFINITY);
val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) ||
val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
}
}
} else { } else {
false false
} }

View file

@ -62,7 +62,7 @@ fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: &TyS,
match type_definition.sty { match type_definition.sty {
TypeVariants::TyFnDef(_, _, fn_type) | TypeVariants::TyFnDef(_, _, fn_type) |
TypeVariants::TyFnPtr(fn_type) => { TypeVariants::TyFnPtr(fn_type) => {
let parameters = fn_type.sig.skip_binder().inputs(); let parameters = fn_type.skip_binder().inputs();
for (argument, parameter) in arguments.iter().zip(parameters.iter()) { for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
match parameter.sty { match parameter.sty {
TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) | TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) |

View file

@ -85,7 +85,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let fn_def_id = cx.tcx.hir.local_def_id(node_id); let fn_def_id = cx.tcx.hir.local_def_id(node_id);
let param_env = ty::ParameterEnvironment::for_item(cx.tcx, node_id); let param_env = ty::ParameterEnvironment::for_item(cx.tcx, node_id);
let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig(); let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig();
let fn_sig = cx.tcx.liberate_late_bound_regions(param_env.free_id_outlive, fn_sig); let fn_sig = cx.tcx.liberate_late_bound_regions(param_env.free_id_outlive, &fn_sig);
for ((input, ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) { for ((input, ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) {

View file

@ -47,7 +47,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) { fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) {
if_let_chain!([ if_let_chain!([
let ExprLit(ref l) = lit.node, let ExprLit(ref l) = lit.node,
let Constant::Int(ref ci) = consts::lit_to_constant(&l.node), let Constant::Int(ref ci) = consts::lit_to_constant(&l.node, cx.tcx, cx.tables.expr_ty(lit)),
let Some(val) = ci.to_u64(), let Some(val) = ci.to_u64(),
val == 1, val == 1,
cx.tables.expr_ty(exp).is_integral() cx.tables.expr_ty(exp).is_integral()

View file

@ -113,7 +113,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass {
fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
let fn_def_id = cx.tcx.hir.local_def_id(fn_id); let fn_def_id = cx.tcx.hir.local_def_id(fn_id);
let fn_ty = cx.tcx.item_type(fn_def_id).fn_sig().skip_binder(); let sig = cx.tcx.item_type(fn_def_id).fn_sig();
let fn_ty = sig.skip_binder();
for (arg, ty) in decl.inputs.iter().zip(fn_ty.inputs()) { for (arg, ty) in decl.inputs.iter().zip(fn_ty.inputs()) {
if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty { if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty {

View file

@ -2,7 +2,6 @@ use regex_syntax;
use rustc::hir::*; use rustc::hir::*;
use rustc::lint::*; use rustc::lint::*;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use std::collections::HashSet; use std::collections::HashSet;
use std::error::Error; use std::error::Error;
@ -151,7 +150,7 @@ fn str_span(base: Span, s: &str, c: usize) -> Span {
} }
fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> {
match ConstContext::with_tables(cx.tcx, cx.tables).eval(e, ExprTypeChecked) { match ConstContext::with_tables(cx.tcx, cx.tables).eval(e) {
Ok(ConstVal::Str(r)) => Some(r), Ok(ConstVal::Str(r)) => Some(r),
_ => None, _ => None,
} }

View file

@ -5,9 +5,10 @@ use rustc::lint::*;
use rustc::ty; use rustc::ty;
use std::cmp::Ordering; use std::cmp::Ordering;
use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::attr::IntType;
use syntax::codemap::Span; use syntax::codemap::Span;
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint,
opt_def_id, last_path_segment}; opt_def_id, last_path_segment, type_size};
use utils::paths; use utils::paths;
/// Handles all the linting of funky types /// Handles all the linting of funky types
@ -907,7 +908,6 @@ fn detect_absurd_comparison<'a>(
fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> { fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> {
use rustc::middle::const_val::ConstVal::*; use rustc::middle::const_val::ConstVal::*;
use rustc_const_math::*; use rustc_const_math::*;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::*; use rustc_const_eval::*;
use types::ExtremeType::*; use types::ExtremeType::*;
@ -918,7 +918,7 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
_ => return None, _ => return None,
}; };
let cv = match ConstContext::with_tables(cx.tcx, cx.tables).eval(expr, ExprTypeChecked) { let cv = match ConstContext::with_tables(cx.tcx, cx.tables).eval(expr) {
Ok(val) => val, Ok(val) => val,
Err(_) => return None, Err(_) => return None,
}; };
@ -1077,7 +1077,13 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
use std::*; use std::*;
if let ExprCast(ref cast_exp, _) = expr.node { if let ExprCast(ref cast_exp, _) = expr.node {
match cx.tables.expr_ty(cast_exp).sty { let pre_cast_ty = cx.tables.expr_ty(cast_exp);
let cast_ty = cx.tables.expr_ty(expr);
// if it's a cast from i32 to u32 wrapping will invalidate all these checks
if type_size(cx, pre_cast_ty) == type_size(cx, cast_ty) {
return None;
}
match pre_cast_ty.sty {
TyInt(int_ty) => { TyInt(int_ty) => {
Some(match int_ty { Some(match int_ty {
IntTy::I8 => (FullInt::S(i8::min_value() as i128), FullInt::S(i8::max_value() as i128)), IntTy::I8 => (FullInt::S(i8::min_value() as i128), FullInt::S(i8::max_value() as i128)),
@ -1107,18 +1113,15 @@ 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_val::ConstVal::*; use rustc::middle::const_val::ConstVal::*;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use rustc_const_math::ConstInt;
match ConstContext::with_tables(cx.tcx, cx.tables).eval(expr, ExprTypeChecked) { match ConstContext::with_tables(cx.tcx, cx.tables).eval(expr) {
Ok(val) => { Ok(val) => {
if let Integral(const_int) = val { if let Integral(const_int) = val {
Some(match const_int.erase_type() { match const_int.int_type() {
ConstInt::InferSigned(x) => FullInt::S(x as i128), IntType::SignedInt(_) => #[allow(cast_possible_wrap)] Some(FullInt::S(const_int.to_u128_unchecked() as i128)),
ConstInt::Infer(x) => FullInt::U(x as u128), IntType::UnsignedInt(_) => Some(FullInt::U(const_int.to_u128_unchecked())),
_ => unreachable!(), }
})
} else { } else {
None None
} }

View file

@ -9,6 +9,7 @@ use rustc::traits::Reveal;
use rustc::traits; use rustc::traits;
use rustc::ty::subst::Subst; use rustc::ty::subst::Subst;
use rustc::ty; use rustc::ty;
use rustc::ty::layout::TargetDataLayout;
use rustc_errors; use rustc_errors;
use std::borrow::Cow; use std::borrow::Cow;
use std::env; use std::env;
@ -781,7 +782,7 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::T
let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item); let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item);
let fn_def_id = cx.tcx.hir.local_def_id(fn_item); let fn_def_id = cx.tcx.hir.local_def_id(fn_item);
let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig(); let fn_sig = cx.tcx.item_type(fn_def_id).fn_sig();
let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, fn_sig); let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, &fn_sig);
fn_sig.output() fn_sig.output()
} }
@ -806,7 +807,7 @@ pub fn same_tys<'a, 'tcx>(
pub fn type_is_unsafe_function(ty: ty::Ty) -> bool { pub fn type_is_unsafe_function(ty: ty::Ty) -> bool {
match ty.sty { match ty.sty {
ty::TyFnDef(_, _, f) | ty::TyFnDef(_, _, f) |
ty::TyFnPtr(f) => f.unsafety == Unsafety::Unsafe, ty::TyFnPtr(f) => f.unsafety() == Unsafety::Unsafe,
_ => false, _ => false,
} }
} }
@ -972,3 +973,9 @@ pub fn is_try(expr: &Expr) -> Option<&Expr> {
None None
} }
pub fn type_size<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>) -> Option<u64> {
cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx|
ty.layout(&infcx).ok().map(|lay| lay.size(&TargetDataLayout::parse(cx.sess())).bytes())
)
}

View file

@ -1,7 +1,6 @@
use rustc::hir::*; use rustc::hir::*;
use rustc::lint::*; use rustc::lint::*;
use rustc::ty; use rustc::ty;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use syntax::codemap::Span; use syntax::codemap::Span;
use utils::{higher, is_copy, snippet, span_lint_and_then}; use utils::{higher, is_copy, snippet, span_lint_and_then};
@ -60,7 +59,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) { fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
let snippet = match *vec_args { let snippet = match *vec_args {
higher::VecArgs::Repeat(elem, len) => { higher::VecArgs::Repeat(elem, len) => {
if ConstContext::with_tables(cx.tcx, cx.tables).eval(len, ExprTypeChecked).is_ok() { if ConstContext::with_tables(cx.tcx, cx.tables).eval(len).is_ok() {
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
} else { } else {
return; return;

View file

@ -36,8 +36,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// TODO - constant_simple does not fold many operations involving floats. // TODO - constant_simple does not fold many operations involving floats.
// That's probably fine for this lint - it's pretty unlikely that someone would // 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. // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(left), let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(cx, left),
let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(right), let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(cx, right),
let Ok(0.0) = lhs_value.parse(), let Ok(0.0) = lhs_value.parse(),
let Ok(0.0) = rhs_value.parse() let Ok(0.0) = rhs_value.parse()
], { ], {

View file

@ -1,99 +0,0 @@
#![feature(rustc_private)]
extern crate clippy_lints;
extern crate rustc;
extern crate rustc_const_eval;
extern crate rustc_const_math;
extern crate syntax;
use clippy_lints::consts::{constant_simple, Constant, FloatWidth};
use rustc_const_math::ConstInt;
use rustc::hir::*;
use syntax::ast::{LitIntType, LitKind, NodeId, StrStyle};
use syntax::codemap::{Spanned, COMMAND_LINE_SP};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::util::ThinVec;
fn spanned<T>(t: T) -> Spanned<T> {
Spanned {
node: t,
span: COMMAND_LINE_SP,
}
}
fn expr(n: Expr_) -> Expr {
Expr {
id: NodeId::new(1),
node: n,
span: COMMAND_LINE_SP,
attrs: ThinVec::new(),
}
}
fn lit(l: LitKind) -> Expr {
expr(ExprLit(P(spanned(l))))
}
fn binop(op: BinOp_, l: Expr, r: Expr) -> Expr {
expr(ExprBinary(spanned(op), P(l), P(r)))
}
fn check(expect: Constant, expr: &Expr) {
assert_eq!(Some(expect), constant_simple(expr))
}
const TRUE: Constant = Constant::Bool(true);
const FALSE: Constant = Constant::Bool(false);
const ZERO: Constant = Constant::Int(ConstInt::Infer(0));
const ONE: Constant = Constant::Int(ConstInt::Infer(1));
const TWO: Constant = Constant::Int(ConstInt::Infer(2));
#[test]
fn test_lit() {
check(TRUE, &lit(LitKind::Bool(true)));
check(FALSE, &lit(LitKind::Bool(false)));
check(ZERO, &lit(LitKind::Int(0, LitIntType::Unsuffixed)));
check(Constant::Str("cool!".into(), StrStyle::Cooked),
&lit(LitKind::Str(Symbol::intern("cool!"), StrStyle::Cooked)));
}
#[test]
fn test_ops() {
check(TRUE, &binop(BiOr, lit(LitKind::Bool(false)), lit(LitKind::Bool(true))));
check(FALSE, &binop(BiAnd, lit(LitKind::Bool(false)), lit(LitKind::Bool(true))));
let litzero = lit(LitKind::Int(0, LitIntType::Unsuffixed));
let litone = lit(LitKind::Int(1, LitIntType::Unsuffixed));
check(TRUE, &binop(BiEq, litzero.clone(), litzero.clone()));
check(TRUE, &binop(BiGe, litzero.clone(), litzero.clone()));
check(TRUE, &binop(BiLe, litzero.clone(), litzero.clone()));
check(FALSE, &binop(BiNe, litzero.clone(), litzero.clone()));
check(FALSE, &binop(BiGt, litzero.clone(), litzero.clone()));
check(FALSE, &binop(BiLt, litzero.clone(), litzero.clone()));
check(ZERO, &binop(BiAdd, litzero.clone(), litzero.clone()));
check(TWO, &binop(BiAdd, litone.clone(), litone.clone()));
check(ONE, &binop(BiSub, litone.clone(), litzero.clone()));
check(ONE, &binop(BiMul, litone.clone(), litone.clone()));
check(ONE, &binop(BiDiv, litone.clone(), litone.clone()));
let half_any = Constant::Float("0.5".into(), FloatWidth::Any);
let half32 = Constant::Float("0.5".into(), FloatWidth::F32);
let half64 = Constant::Float("0.5".into(), FloatWidth::F64);
let pos_zero = Constant::Float("0.0".into(), FloatWidth::F64);
let neg_zero = Constant::Float("-0.0".into(), FloatWidth::F64);
assert_eq!(pos_zero, pos_zero);
assert_eq!(neg_zero, neg_zero);
assert_eq!(None, pos_zero.partial_cmp(&neg_zero));
assert_eq!(half_any, half32);
assert_eq!(half_any, half64);
// for transitivity
assert_eq!(half32, half64);
assert_eq!(Constant::Int(ConstInt::Infer(0)), Constant::Int(ConstInt::U8(0)));
assert_eq!(Constant::Int(ConstInt::Infer(0)), Constant::Int(ConstInt::I8(0)));
assert_eq!(Constant::Int(ConstInt::InferSigned(-1)), Constant::Int(ConstInt::I8(-1)));
}

View file

@ -3,33 +3,79 @@
#![deny(invalid_upcast_comparisons)] #![deny(invalid_upcast_comparisons)]
#![allow(unused, eq_op, no_effect, unnecessary_operation)] #![allow(unused, eq_op, no_effect, unnecessary_operation)]
fn mk_value<T>() -> T { unimplemented!() }
fn main() { fn main() {
let zero: u32 = 0; let u32: u32 = mk_value();
let u8_max: u8 = 255; let u8: u8 = mk_value();
let i32: i32 = mk_value();
let i8: i8 = mk_value();
(u8_max as u32) > 300; // always false, since no u8 can be > 300
(u8_max as u32) > 20; (u8 as u32) > 300;
(u8 as i32) > 300;
(u8 as u32) == 300;
(u8 as i32) == 300;
300 < (u8 as u32);
300 < (u8 as i32);
300 == (u8 as u32);
300 == (u8 as i32);
// inverted of the above
(u8 as u32) <= 300;
(u8 as i32) <= 300;
(u8 as u32) != 300;
(u8 as i32) != 300;
300 >= (u8 as u32);
300 >= (u8 as i32);
300 != (u8 as u32);
300 != (u8 as i32);
(zero as i32) < -5; // always false, since u8 -> i32 doesn't wrap
(zero as i32) < 10; (u8 as i32) < 0;
-5 != (u8 as i32);
// inverted of the above
(u8 as i32) >= 0;
-5 == (u8 as i32);
-5 < (zero as i32); // always false, since no u8 can be 1337
0 <= (zero as i32); 1337 == (u8 as i32);
0 < (zero as i32); 1337 == (u8 as u32);
// inverted of the above
1337 != (u8 as i32);
1337 != (u8 as u32);
-5 > (zero as i32);
-5 >= (u8_max as i32);
1337 == (u8_max as i32);
-5 == (zero as i32);
-5 != (u8_max as i32);
// Those are Ok: // Those are Ok:
42 == (u8_max as i32); (u8 as u32) > 20;
42 != (u8_max as i32); 42 == (u8 as i32);
42 > (u8_max as i32); 42 != (u8 as i32);
(u8_max as i32) == 42; 42 > (u8 as i32);
(u8_max as i32) != 42; (u8 as i32) == 42;
(u8_max as i32) > 42; (u8 as i32) != 42;
(u8_max as i32) < 42; (u8 as i32) > 42;
(u8 as i32) < 42;
(u8 as i8) == -1;
(u8 as i8) != -1;
(u8 as i32) > -1;
(u8 as i32) < -1;
(u32 as i32) < -5;
(u32 as i32) < 10;
(i8 as u8) == 1;
(i8 as u8) != 1;
(i8 as u8) < 1;
(i8 as u8) > 1;
(i32 as u32) < 5;
(i32 as u32) < 10;
-5 < (u32 as i32);
0 <= (u32 as i32);
0 < (u32 as i32);
-5 > (u32 as i32);
-5 >= (u8 as i32);
-5 == (u32 as i32);
} }

View file

@ -1,8 +1,8 @@
error: because of the numeric bounds on `u8_max` prior to casting, this expression is always false error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:10:5 --> $DIR/invalid_upcast_comparisons.rs:16:5
| |
10 | (u8_max as u32) > 300; 16 | (u8 as u32) > 300;
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
| |
note: lint level defined here note: lint level defined here
--> $DIR/invalid_upcast_comparisons.rs:4:9 --> $DIR/invalid_upcast_comparisons.rs:4:9
@ -10,53 +10,161 @@ note: lint level defined here
4 | #![deny(invalid_upcast_comparisons)] 4 | #![deny(invalid_upcast_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `zero` prior to casting, this expression is always false error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:13:5
|
13 | (zero as i32) < -5;
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `zero` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:16:5
|
16 | -5 < (zero as i32);
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `zero` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:17:5 --> $DIR/invalid_upcast_comparisons.rs:17:5
| |
17 | 0 <= (zero as i32); 17 | (u8 as i32) > 300;
| ^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:18:5
|
18 | (u8 as u32) == 300;
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `zero` prior to casting, this expression is always false error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:19:5
|
19 | (u8 as i32) == 300;
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:20:5 --> $DIR/invalid_upcast_comparisons.rs:20:5
| |
20 | -5 > (zero as i32); 20 | 300 < (u8 as u32);
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8_max` prior to casting, this expression is always false error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:21:5 --> $DIR/invalid_upcast_comparisons.rs:21:5
| |
21 | -5 >= (u8_max as i32); 21 | 300 < (u8 as i32);
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8_max` prior to casting, this expression is always false error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:22:5 --> $DIR/invalid_upcast_comparisons.rs:22:5
| |
22 | 1337 == (u8_max as i32); 22 | 300 == (u8 as u32);
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `zero` prior to casting, this expression is always false error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:24:5 --> $DIR/invalid_upcast_comparisons.rs:23:5
| |
24 | -5 == (zero as i32); 23 | 300 == (u8 as i32);
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8_max` prior to casting, this expression is always true error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:25:5 --> $DIR/invalid_upcast_comparisons.rs:25:5
| |
25 | -5 != (u8_max as i32); 25 | (u8 as u32) <= 300;
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: aborting due to 9 previous errors error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:26:5
|
26 | (u8 as i32) <= 300;
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:27:5
|
27 | (u8 as u32) != 300;
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:28:5
|
28 | (u8 as i32) != 300;
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:29:5
|
29 | 300 >= (u8 as u32);
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:30:5
|
30 | 300 >= (u8 as i32);
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:31:5
|
31 | 300 != (u8 as u32);
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:32:5
|
32 | 300 != (u8 as i32);
| ^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:35:5
|
35 | (u8 as i32) < 0;
| ^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:36:5
|
36 | -5 != (u8 as i32);
| ^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:38:5
|
38 | (u8 as i32) >= 0;
| ^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:39:5
|
39 | -5 == (u8 as i32);
| ^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:42:5
|
42 | 1337 == (u8 as i32);
| ^^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:43:5
|
43 | 1337 == (u8 as u32);
| ^^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:45:5
|
45 | 1337 != (u8 as i32);
| ^^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:46:5
|
46 | 1337 != (u8 as u32);
| ^^^^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always true
--> $DIR/invalid_upcast_comparisons.rs:61:5
|
61 | (u8 as i32) > -1;
| ^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:62:5
|
62 | (u8 as i32) < -1;
| ^^^^^^^^^^^^^^^^
error: because of the numeric bounds on `u8` prior to casting, this expression is always false
--> $DIR/invalid_upcast_comparisons.rs:78:5
|
78 | -5 >= (u8 as i32);
| ^^^^^^^^^^^^^^^^^
error: aborting due to 27 previous errors