rustup const eval changes

This commit is contained in:
Oliver 'ker' Schneider 2016-03-15 20:09:53 +01:00
parent 20123eef98
commit d65953330b
7 changed files with 66 additions and 99 deletions

View file

@ -3,6 +3,7 @@ use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal};
use rustc::middle::ty::TyArray;
use rustc_front::hir::*;
use rustc_const_eval::ConstInt;
use syntax::ast::RangeLimits;
use utils;
@ -62,11 +63,11 @@ impl LateLintPass for ArrayIndexing {
// Array with known size can be checked statically
let ty = cx.tcx.expr_ty(array);
if let TyArray(_, size) = ty.sty {
let size = size as u64;
let size = ConstInt::Infer(size as u64);
// Index is a constant uint
let const_index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None);
if let Ok(ConstVal::Uint(const_index)) = const_index {
if let Ok(ConstVal::Integral(const_index)) = const_index {
if size <= const_index {
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds");
}
@ -115,24 +116,24 @@ impl LateLintPass for ArrayIndexing {
fn to_const_range(start: Option<Option<ConstVal>>,
end: Option<Option<ConstVal>>,
limits: RangeLimits,
array_size: u64)
-> Option<(u64, u64)> {
array_size: ConstInt)
-> Option<(ConstInt, ConstInt)> {
let start = match start {
Some(Some(ConstVal::Uint(x))) => x,
Some(Some(ConstVal::Integral(x))) => x,
Some(_) => return None,
None => 0,
None => ConstInt::Infer(0),
};
let end = match end {
Some(Some(ConstVal::Uint(x))) => {
Some(Some(ConstVal::Integral(x))) => {
if limits == RangeLimits::Closed {
x
} else {
x - 1
(x - ConstInt::Infer(1)).expect("x > 0")
}
}
Some(_) => return None,
None => array_size - 1,
None => (array_size - ConstInt::Infer(1)).expect("array_size > 0"),
};
Some((start, end))

View file

@ -271,7 +271,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> {
}
}
.and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None, None))
.and_then(|l| fetch_int_literal(cx, l))
.and_then(|(l, _ty)| fetch_int_literal(cx, l))
}
_ => None,
}

View file

@ -347,7 +347,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}
// separate if lets to avoid double borrowing the def_map
if let Some(id) = maybe_id {
if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None, None) {
if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, id, None, None) {
let ret = self.expr(const_expr);
if ret.is_some() {
self.needed_resolution = true;

View file

@ -1,11 +1,9 @@
//! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`
use rustc::lint::*;
use syntax::ast::{IntTy, UintTy};
use syntax::attr::*;
use rustc_front::hir::*;
use rustc::middle::const_eval::{ConstVal, EvalHint, eval_const_expr_partial};
use rustc::middle::ty;
use utils::span_lint;
/// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`.
@ -35,12 +33,10 @@ impl LateLintPass for EnumClikeUnportableVariant {
for var in &def.variants {
let variant = &var.node;
if let Some(ref disr) = variant.disr_expr {
let cv = eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None);
let bad = match (cv, &cx.tcx.expr_ty(&**disr).sty) {
(Ok(ConstVal::Int(i)), &ty::TyInt(IntTy::Is)) => i as i32 as i64 != i,
(Ok(ConstVal::Uint(i)), &ty::TyInt(IntTy::Is)) => i as i32 as u64 != i,
(Ok(ConstVal::Int(i)), &ty::TyUint(UintTy::Us)) => (i < 0) || (i as u32 as i64 != i),
(Ok(ConstVal::Uint(i)), &ty::TyUint(UintTy::Us)) => i as u32 as u64 != i,
use rustc_const_eval::*;
let bad = match eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None) {
Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i,
Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i,
_ => false,
};
if bad {

View file

@ -429,10 +429,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
// who think that this will iterate from the larger value to the
// smaller value.
let (sup, eq) = match (start_idx, end_idx) {
(ConstVal::Int(start_idx), ConstVal::Int(end_idx)) => {
(start_idx > end_idx, start_idx == end_idx)
}
(ConstVal::Uint(start_idx), ConstVal::Uint(end_idx)) => {
(ConstVal::Integral(start_idx), ConstVal::Integral(end_idx)) => {
(start_idx > end_idx, start_idx == end_idx)
}
_ => (false, false),

View file

@ -1,9 +1,9 @@
use rustc::lint::*;
use rustc::middle::const_eval::ConstVal::{Int, Uint};
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal};
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_const_eval::ConstInt;
use std::cmp::Ordering;
use syntax::ast::LitKind;
use syntax::codemap::Span;
@ -288,22 +288,19 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) {
if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms);
let overlap = match type_ranges(&ranges) {
TypedRanges::IntRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)),
TypedRanges::UintRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)),
TypedRanges::None => None,
};
if let Some((start, end)) = overlap {
let type_ranges = type_ranges(&ranges);
if !type_ranges.is_empty() {
if let Some((start, end)) = overlapping(&type_ranges) {
span_note_and_lint(cx,
MATCH_OVERLAPPING_ARM,
start,
start.span,
"some ranges overlap",
end,
end.span,
"overlaps with this");
}
}
}
}
fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) {
if has_only_ref_pats(arms) {
@ -370,24 +367,13 @@ pub struct SpannedRange<T> {
pub node: (T, T),
}
#[derive(Debug)]
enum TypedRanges {
IntRanges(Vec<SpannedRange<i64>>),
UintRanges(Vec<SpannedRange<u64>>),
None,
}
type TypedRanges = Vec<SpannedRange<ConstInt>>;
/// 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<ConstVal>]) -> TypedRanges {
if ranges.is_empty() {
TypedRanges::None
} else {
match ranges[0].node {
(Int(_), Int(_)) => {
TypedRanges::IntRanges(ranges.iter()
.filter_map(|range| {
if let (Int(start), Int(end)) = range.node {
ranges.iter().filter_map(|range| {
if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node {
Some(SpannedRange {
span: range.span,
node: (start, end),
@ -396,25 +382,7 @@ fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges {
None
}
})
.collect())
}
(Uint(_), Uint(_)) => {
TypedRanges::UintRanges(ranges.iter()
.filter_map(|range| {
if let (Uint(start), Uint(end)) = range.node {
Some(SpannedRange {
span: range.span,
node: (start, end),
})
} else {
None
}
})
.collect())
}
_ => TypedRanges::None,
}
}
.collect()
}
fn is_unit_expr(expr: &Expr) -> bool {

View file

@ -673,6 +673,7 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use types::ExtremeType::*;
use rustc::middle::const_eval::ConstVal::*;
use rustc_const_eval::*;
let ty = &cx.tcx.expr_ty(expr).sty;
@ -687,33 +688,37 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx
};
let which = match (ty, cv) {
(&ty::TyBool, Bool(false)) => Minimum,
(&ty::TyBool, Bool(false)) |
(&ty::TyInt(IntTy::Is), Int(x)) if x == ::std::isize::MIN as i64 => Minimum,
(&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MIN as i64 => Minimum,
(&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MIN as i64 => Minimum,
(&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MIN as i64 => Minimum,
(&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MIN as i64 => Minimum,
(&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) |
(&ty::TyInt(IntTy::Is), 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::TyUint(UintTy::Us), Uint(x)) if x == ::std::usize::MIN as u64 => Minimum,
(&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MIN as u64 => Minimum,
(&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MIN as u64 => Minimum,
(&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MIN as u64 => Minimum,
(&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MIN as u64 => Minimum,
(&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) |
(&ty::TyUint(UintTy::Us), 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))) => Minimum,
(&ty::TyBool, Bool(true)) => Maximum,
(&ty::TyBool, Bool(true)) |
(&ty::TyInt(IntTy::Is), Int(x)) if x == ::std::isize::MAX as i64 => Maximum,
(&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MAX as i64 => Maximum,
(&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MAX as i64 => Maximum,
(&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MAX as i64 => Maximum,
(&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MAX as i64 => Maximum,
(&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) |
(&ty::TyInt(IntTy::Is), 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::TyUint(UintTy::Us), Uint(x)) if x == ::std::usize::MAX as u64 => Maximum,
(&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MAX as u64 => Maximum,
(&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MAX as u64 => Maximum,
(&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MAX as u64 => Maximum,
(&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MAX as u64 => Maximum,
(&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) |
(&ty::TyUint(UintTy::Us), 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))) => Maximum,
_ => return None,
};