Merge ConstMathError into EvalErrorKind
This commit is contained in:
parent
671b2a5964
commit
cefcf0548e
12 changed files with 65 additions and 115 deletions
|
@ -525,16 +525,26 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
|
|||
predicates
|
||||
});
|
||||
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ::mir::interpret::EvalError<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
self.kind.hash_stable(hcx, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ::mir::interpret::EvalErrorKind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use mir::interpret::EvalErrorKind::*;
|
||||
|
||||
mem::discriminant(&self.kind).hash_stable(hcx, hasher);
|
||||
mem::discriminant(&self).hash_stable(hcx, hasher);
|
||||
|
||||
match self.kind {
|
||||
match *self {
|
||||
DanglingPointerDeref |
|
||||
DoubleFree |
|
||||
InvalidMemoryAccess |
|
||||
|
@ -565,8 +575,10 @@ for ::mir::interpret::EvalError<'gcx> {
|
|||
TypeckError |
|
||||
DerefFunctionPointer |
|
||||
ExecuteMemory |
|
||||
ReferencedConstant |
|
||||
OverflowingMath => {}
|
||||
OverflowNeg |
|
||||
RemainderByZero |
|
||||
DivisionByZero |
|
||||
ReferencedConstant => {}
|
||||
MachineError(ref err) => err.hash_stable(hcx, hasher),
|
||||
FunctionPointerTyMismatch(a, b) => {
|
||||
a.hash_stable(hcx, hasher);
|
||||
|
@ -590,10 +602,6 @@ for ::mir::interpret::EvalError<'gcx> {
|
|||
a.hash_stable(hcx, hasher);
|
||||
b.hash_stable(hcx, hasher)
|
||||
},
|
||||
Math(sp, ref err) => {
|
||||
sp.hash_stable(hcx, hasher);
|
||||
err.hash_stable(hcx, hasher)
|
||||
},
|
||||
Intrinsic(ref s) => s.hash_stable(hcx, hasher),
|
||||
InvalidChar(c) => c.hash_stable(hcx, hasher),
|
||||
AbiViolation(ref s) => s.hash_stable(hcx, hasher),
|
||||
|
@ -665,27 +673,11 @@ for ::mir::interpret::EvalError<'gcx> {
|
|||
Layout(lay) => lay.hash_stable(hcx, hasher),
|
||||
HeapAllocNonPowerOfTwoAlignment(n) => n.hash_stable(hcx, hasher),
|
||||
PathNotFound(ref v) => v.hash_stable(hcx, hasher),
|
||||
Overflow(op) => op.hash_stable(hcx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum mir::interpret::ConstMathErr {
|
||||
Overflow(op),
|
||||
DivisionByZero,
|
||||
RemainderByZero,
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum mir::interpret::Op {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Rem,
|
||||
Shr,
|
||||
Shl,
|
||||
Neg,
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum mir::interpret::Lock {
|
||||
NoLock,
|
||||
WriteLock(dl),
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::error::Error;
|
||||
use std::{fmt, env};
|
||||
|
||||
use mir;
|
||||
|
@ -30,7 +29,7 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum EvalErrorKind<'tcx> {
|
||||
/// This variant is used by machines to signal their own errors that do not
|
||||
/// match an existing variant
|
||||
|
@ -60,9 +59,11 @@ pub enum EvalErrorKind<'tcx> {
|
|||
DerefFunctionPointer,
|
||||
ExecuteMemory,
|
||||
ArrayIndexOutOfBounds(Span, u64, u64),
|
||||
Math(Span, ConstMathErr),
|
||||
Overflow(mir::BinOp),
|
||||
OverflowNeg,
|
||||
DivisionByZero,
|
||||
RemainderByZero,
|
||||
Intrinsic(String),
|
||||
OverflowingMath,
|
||||
InvalidChar(u128),
|
||||
StackFrameLimitReached,
|
||||
OutOfTls,
|
||||
|
@ -124,10 +125,10 @@ pub enum EvalErrorKind<'tcx> {
|
|||
|
||||
pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
|
||||
|
||||
impl<'tcx> Error for EvalError<'tcx> {
|
||||
fn description(&self) -> &str {
|
||||
impl<'tcx> EvalErrorKind<'tcx> {
|
||||
pub fn description(&self) -> &str {
|
||||
use self::EvalErrorKind::*;
|
||||
match self.kind {
|
||||
match *self {
|
||||
MachineError(ref inner) => inner,
|
||||
FunctionPointerTyMismatch(..) =>
|
||||
"tried to call a function through a function pointer of a different type",
|
||||
|
@ -176,12 +177,8 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"tried to treat a memory pointer as a function pointer",
|
||||
ArrayIndexOutOfBounds(..) =>
|
||||
"array index out of bounds",
|
||||
Math(..) =>
|
||||
"mathematical operation failed",
|
||||
Intrinsic(..) =>
|
||||
"intrinsic failed",
|
||||
OverflowingMath =>
|
||||
"attempted to do overflowing math",
|
||||
NoMirFor(..) =>
|
||||
"mir not found",
|
||||
InvalidChar(..) =>
|
||||
|
@ -239,6 +236,17 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"encountered constants with type errors, stopping evaluation",
|
||||
ReferencedConstant =>
|
||||
"referenced constant has errors",
|
||||
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
|
||||
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
|
||||
Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
|
||||
Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
|
||||
Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
|
||||
OverflowNeg => "attempt to negate with overflow",
|
||||
Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
|
||||
Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
|
||||
Overflow(op) => bug!("{:?} cannot overflow", op),
|
||||
DivisionByZero => "attempt to divide by zero",
|
||||
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,8 +288,6 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
write!(f, "tried to reallocate memory from {} to {}", old, new),
|
||||
DeallocatedWrongMemoryKind(ref old, ref new) =>
|
||||
write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
|
||||
Math(_, ref err) =>
|
||||
write!(f, "{}", err.description()),
|
||||
Intrinsic(ref err) =>
|
||||
write!(f, "{}", err),
|
||||
InvalidChar(c) =>
|
||||
|
@ -299,45 +305,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
write!(f, "{}", inner),
|
||||
IncorrectAllocationInformation(size, size2, align, align2) =>
|
||||
write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2),
|
||||
_ => write!(f, "{}", self.description()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum ConstMathErr {
|
||||
Overflow(Op),
|
||||
DivisionByZero,
|
||||
RemainderByZero,
|
||||
}
|
||||
pub use self::ConstMathErr::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum Op {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Rem,
|
||||
Shr,
|
||||
Shl,
|
||||
Neg,
|
||||
}
|
||||
|
||||
impl ConstMathErr {
|
||||
pub fn description(&self) -> &'static str {
|
||||
use self::Op::*;
|
||||
match *self {
|
||||
Overflow(Add) => "attempt to add with overflow",
|
||||
Overflow(Sub) => "attempt to subtract with overflow",
|
||||
Overflow(Mul) => "attempt to multiply with overflow",
|
||||
Overflow(Div) => "attempt to divide with overflow",
|
||||
Overflow(Rem) => "attempt to calculate the remainder with overflow",
|
||||
Overflow(Neg) => "attempt to negate with overflow",
|
||||
Overflow(Shr) => "attempt to shift right with overflow",
|
||||
Overflow(Shl) => "attempt to shift left with overflow",
|
||||
DivisionByZero => "attempt to divide by zero",
|
||||
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
|
||||
_ => write!(f, "{}", self.kind.description()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ macro_rules! err {
|
|||
mod error;
|
||||
mod value;
|
||||
|
||||
pub use self::error::{EvalError, EvalResult, EvalErrorKind, Op, ConstMathErr};
|
||||
pub use self::error::{EvalError, EvalResult, EvalErrorKind};
|
||||
|
||||
pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
|
||||
|
||||
|
@ -23,7 +23,7 @@ use std::iter;
|
|||
use syntax::ast::Mutability;
|
||||
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Lock {
|
||||
NoLock,
|
||||
WriteLock(DynamicLifetime),
|
||||
|
@ -31,13 +31,13 @@ pub enum Lock {
|
|||
ReadLock(Vec<DynamicLifetime>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct DynamicLifetime {
|
||||
pub frame: usize,
|
||||
pub region: Option<region::Scope>, // "None" indicates "until the function ends"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||
pub enum AccessKind {
|
||||
Read,
|
||||
Write,
|
||||
|
@ -88,12 +88,12 @@ pub trait PointerArithmetic: layout::HasDataLayout {
|
|||
|
||||
fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_signed_offset(val, i as i128);
|
||||
if over { err!(OverflowingMath) } else { Ok(res) }
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_offset(val, i);
|
||||
if over { err!(OverflowingMath) } else { Ok(res) }
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 {
|
||||
|
|
|
@ -25,7 +25,7 @@ use rustc_serialize as serialize;
|
|||
use hir::def::CtorKind;
|
||||
use hir::def_id::DefId;
|
||||
use mir::visit::MirVisitable;
|
||||
use mir::interpret::{Value, PrimVal, ConstMathErr};
|
||||
use mir::interpret::{Value, PrimVal, EvalErrorKind};
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
|
@ -1211,7 +1211,7 @@ pub enum AssertMessage<'tcx> {
|
|||
len: Operand<'tcx>,
|
||||
index: Operand<'tcx>
|
||||
},
|
||||
Math(ConstMathErr),
|
||||
Math(EvalErrorKind<'tcx>),
|
||||
GeneratorResumedAfterReturn,
|
||||
GeneratorResumedAfterPanic,
|
||||
}
|
||||
|
@ -1920,9 +1920,9 @@ pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Resul
|
|||
(Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
|
||||
(Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
|
||||
(Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F32)) =>
|
||||
write!(f, "{}", Single::from_bits(bits)),
|
||||
write!(f, "{}f32", Single::from_bits(bits)),
|
||||
(Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F64)) =>
|
||||
write!(f, "{}", Double::from_bits(bits)),
|
||||
write!(f, "{}f64", Double::from_bits(bits)),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
|
||||
|
|
|
@ -149,7 +149,7 @@ pub const FAT_PTR_ADDR: usize = 0;
|
|||
/// - For a slice, this is the length.
|
||||
pub const FAT_PTR_EXTRA: usize = 1;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum LayoutError<'tcx> {
|
||||
Unknown(Ty<'tcx>),
|
||||
SizeOverflow(Ty<'tcx>)
|
||||
|
|
|
@ -505,9 +505,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
|||
DerefFunctionPointer => DerefFunctionPointer,
|
||||
ExecuteMemory => ExecuteMemory,
|
||||
ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b),
|
||||
Math(sp, ref err) => Math(sp, err.clone()),
|
||||
Intrinsic(ref s) => Intrinsic(s.clone()),
|
||||
OverflowingMath => OverflowingMath,
|
||||
InvalidChar(c) => InvalidChar(c),
|
||||
StackFrameLimitReached => StackFrameLimitReached,
|
||||
OutOfTls => OutOfTls,
|
||||
|
@ -568,6 +566,10 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
|||
UnimplementedTraitSelection => UnimplementedTraitSelection,
|
||||
TypeckError => TypeckError,
|
||||
ReferencedConstant => ReferencedConstant,
|
||||
OverflowNeg => OverflowNeg,
|
||||
Overflow(op) => Overflow(op),
|
||||
DivisionByZero => DivisionByZero,
|
||||
RemainderByZero => RemainderByZero,
|
||||
};
|
||||
Some(interpret::EvalError {
|
||||
kind: kind,
|
||||
|
|
|
@ -20,7 +20,7 @@ use rustc::middle::const_val::ConstVal;
|
|||
use rustc::middle::region;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::interpret::{Value, PrimVal, ConstMathErr, Op};
|
||||
use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
|
||||
use syntax_pos::Span;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
@ -85,7 +85,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
this.cfg.push_assign(block, source_info, &is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval));
|
||||
|
||||
let err = ConstMathErr::Overflow(Op::Neg);
|
||||
let err = EvalErrorKind::OverflowNeg;
|
||||
block = this.assert(block, Operand::Move(is_min), false,
|
||||
AssertMessage::Math(err), expr_span);
|
||||
}
|
||||
|
@ -310,16 +310,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let val = result_value.clone().field(val_fld, ty);
|
||||
let of = result_value.field(of_fld, bool_ty);
|
||||
|
||||
let err = ConstMathErr::Overflow(match op {
|
||||
BinOp::Add => Op::Add,
|
||||
BinOp::Sub => Op::Sub,
|
||||
BinOp::Mul => Op::Mul,
|
||||
BinOp::Shl => Op::Shl,
|
||||
BinOp::Shr => Op::Shr,
|
||||
_ => {
|
||||
bug!("MIR build_binary_op: {:?} is not checkable", op)
|
||||
}
|
||||
});
|
||||
let err = EvalErrorKind::Overflow(op);
|
||||
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(err), span);
|
||||
|
@ -331,11 +322,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// and 2. there are two possible failure cases, divide-by-zero and overflow.
|
||||
|
||||
let (zero_err, overflow_err) = if op == BinOp::Div {
|
||||
(ConstMathErr::DivisionByZero,
|
||||
ConstMathErr::Overflow(Op::Div))
|
||||
(EvalErrorKind::DivisionByZero,
|
||||
EvalErrorKind::Overflow(op))
|
||||
} else {
|
||||
(ConstMathErr::RemainderByZero,
|
||||
ConstMathErr::Overflow(Op::Rem))
|
||||
(EvalErrorKind::RemainderByZero,
|
||||
EvalErrorKind::Overflow(op))
|
||||
};
|
||||
|
||||
// Check for / 0
|
||||
|
|
|
@ -513,7 +513,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
// it emits in debug mode) is performance, but it doesn't cost us any performance in miri.
|
||||
// If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops,
|
||||
// we have to go back to just ignoring the overflow here.
|
||||
return err!(OverflowingMath);
|
||||
return err!(Overflow(bin_op));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,7 +269,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
(Neg, ty::TyFloat(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
|
||||
(Neg, ty::TyFloat(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
|
||||
|
||||
(Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowingMath),
|
||||
(Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowNeg),
|
||||
(Neg, _) => (-(bytes as i128)) as u128,
|
||||
};
|
||||
|
||||
|
|
|
@ -160,9 +160,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
.to_u64()?;
|
||||
err!(ArrayIndexOutOfBounds(span, len, index))
|
||||
}
|
||||
Math(ref err) => {
|
||||
err!(Math(terminator.source_info.span, err.clone()))
|
||||
}
|
||||
Math(ref err) => Err(err.clone().into()),
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic => unimplemented!(),
|
||||
};
|
||||
|
|
|
@ -328,7 +328,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
} else {
|
||||
if overflow {
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
let mut err = EvalErrorKind::OverflowingMath.into();
|
||||
let mut err = EvalErrorKind::Overflow(op).into();
|
||||
ecx.report(&mut err, false, Some(span));
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -311,10 +311,9 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
|||
// checked operation, just a comparison with the minimum
|
||||
// value, so we have to check for the assert message.
|
||||
if !bx.cx.check_overflow {
|
||||
use rustc::mir::interpret::ConstMathErr::Overflow;
|
||||
use rustc::mir::interpret::Op::Neg;
|
||||
use rustc::mir::interpret::EvalErrorKind::OverflowNeg;
|
||||
|
||||
if let mir::AssertMessage::Math(Overflow(Neg)) = *msg {
|
||||
if let mir::AssertMessage::Math(OverflowNeg) = *msg {
|
||||
const_cond = Some(expected);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue