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

View File

@@ -347,7 +347,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
} }
// separate if lets to avoid double borrowing the def_map // separate if lets to avoid double borrowing the def_map
if let Some(id) = maybe_id { 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); let ret = self.expr(const_expr);
if ret.is_some() { if ret.is_some() {
self.needed_resolution = true; 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` //! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`
use rustc::lint::*; use rustc::lint::*;
use syntax::ast::{IntTy, UintTy};
use syntax::attr::*; use syntax::attr::*;
use rustc_front::hir::*; use rustc_front::hir::*;
use rustc::middle::const_eval::{ConstVal, EvalHint, eval_const_expr_partial}; use rustc::middle::const_eval::{ConstVal, EvalHint, eval_const_expr_partial};
use rustc::middle::ty;
use utils::span_lint; 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`. /// **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 { for var in &def.variants {
let variant = &var.node; let variant = &var.node;
if let Some(ref disr) = variant.disr_expr { if let Some(ref disr) = variant.disr_expr {
let cv = eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None); use rustc_const_eval::*;
let bad = match (cv, &cx.tcx.expr_ty(&**disr).sty) { let bad = match eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None) {
(Ok(ConstVal::Int(i)), &ty::TyInt(IntTy::Is)) => i as i32 as i64 != i, Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i,
(Ok(ConstVal::Uint(i)), &ty::TyInt(IntTy::Is)) => i as i32 as u64 != i, Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != 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,
_ => false, _ => false,
}; };
if bad { 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 // who think that this will iterate from the larger value to the
// smaller value. // smaller value.
let (sup, eq) = match (start_idx, end_idx) { let (sup, eq) = match (start_idx, end_idx) {
(ConstVal::Int(start_idx), ConstVal::Int(end_idx)) => { (ConstVal::Integral(start_idx), ConstVal::Integral(end_idx)) => {
(start_idx > end_idx, start_idx == end_idx)
}
(ConstVal::Uint(start_idx), ConstVal::Uint(end_idx)) => {
(start_idx > end_idx, start_idx == end_idx) (start_idx > end_idx, start_idx == end_idx)
} }
_ => (false, false), _ => (false, false),

View File

@@ -1,9 +1,9 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::middle::const_eval::ConstVal::{Int, Uint};
use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal};
use rustc::middle::ty; use rustc::middle::ty;
use rustc_front::hir::*; use rustc_front::hir::*;
use rustc_const_eval::ConstInt;
use std::cmp::Ordering; use std::cmp::Ordering;
use syntax::ast::LitKind; use syntax::ast::LitKind;
use syntax::codemap::Span; use syntax::codemap::Span;
@@ -288,21 +288,18 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) {
if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() { if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms); let ranges = all_ranges(cx, arms);
let overlap = match type_ranges(&ranges) { let type_ranges = type_ranges(&ranges);
TypedRanges::IntRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), if !type_ranges.is_empty() {
TypedRanges::UintRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), if let Some((start, end)) = overlapping(&type_ranges) {
TypedRanges::None => None,
};
if let Some((start, end)) = overlap {
span_note_and_lint(cx, span_note_and_lint(cx,
MATCH_OVERLAPPING_ARM, MATCH_OVERLAPPING_ARM,
start, start.span,
"some ranges overlap", "some ranges overlap",
end, end.span,
"overlaps with this"); "overlaps with this");
} }
} }
}
} }
fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) { fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) {
@@ -370,24 +367,13 @@ pub struct SpannedRange<T> {
pub node: (T, T), pub node: (T, T),
} }
#[derive(Debug)] type TypedRanges = Vec<SpannedRange<ConstInt>>;
enum TypedRanges {
IntRanges(Vec<SpannedRange<i64>>),
UintRanges(Vec<SpannedRange<u64>>),
None,
}
/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than /// 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. /// `Uint` and `Int` probably don't make sense.
fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges { fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges {
if ranges.is_empty() { ranges.iter().filter_map(|range| {
TypedRanges::None if let (ConstVal::Integral(start), ConstVal::Integral(end)) = range.node {
} else {
match ranges[0].node {
(Int(_), Int(_)) => {
TypedRanges::IntRanges(ranges.iter()
.filter_map(|range| {
if let (Int(start), Int(end)) = range.node {
Some(SpannedRange { Some(SpannedRange {
span: range.span, span: range.span,
node: (start, end), node: (start, end),
@@ -396,25 +382,7 @@ fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges {
None None
} }
}) })
.collect()) .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,
}
}
} }
fn is_unit_expr(expr: &Expr) -> bool { 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 rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use types::ExtremeType::*; use types::ExtremeType::*;
use rustc::middle::const_eval::ConstVal::*; use rustc::middle::const_eval::ConstVal::*;
use rustc_const_eval::*;
let ty = &cx.tcx.expr_ty(expr).sty; 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) { 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::Is), Integral(Isize(Is32(::std::i32::MIN)))) |
(&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MIN as i64 => Minimum, (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) |
(&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MIN as i64 => Minimum, (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) |
(&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MIN as i64 => Minimum, (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) |
(&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MIN as i64 => Minimum, (&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::Us), Integral(Usize(Us32(::std::u32::MIN)))) |
(&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MIN as u64 => Minimum, (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) |
(&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MIN as u64 => Minimum, (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) |
(&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MIN as u64 => Minimum, (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MIN))) |
(&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MIN as u64 => Minimum, (&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::Is), Integral(Isize(Is32(::std::i32::MAX)))) |
(&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MAX as i64 => Maximum, (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) |
(&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MAX as i64 => Maximum, (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) |
(&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MAX as i64 => Maximum, (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) |
(&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MAX as i64 => Maximum, (&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::Us), Integral(Usize(Us32(::std::u32::MAX)))) |
(&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MAX as u64 => Maximum, (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) |
(&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MAX as u64 => Maximum, (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) |
(&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MAX as u64 => Maximum, (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MAX))) |
(&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MAX as u64 => Maximum, (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MAX))) |
(&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MAX))) => Maximum,
_ => return None, _ => return None,
}; };