From cefcf0548ec06cfdd00de4d02ee9c1b0c6cfe6fa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 26 Apr 2018 14:52:59 +0200 Subject: [PATCH] Merge ConstMathError into EvalErrorKind --- src/librustc/ich/impls_ty.rs | 42 +++++------- src/librustc/mir/interpret/error.rs | 72 ++++++-------------- src/librustc/mir/interpret/mod.rs | 12 ++-- src/librustc/mir/mod.rs | 8 +-- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/structural_impls.rs | 6 +- src/librustc_mir/build/expr/as_rvalue.rs | 23 ++----- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/interpret/operator.rs | 2 +- src/librustc_mir/interpret/terminator/mod.rs | 4 +- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_trans/mir/block.rs | 5 +- 12 files changed, 65 insertions(+), 115 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 92a8ee28168cf..a5447a3145afe 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -525,16 +525,26 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { predicates }); + impl<'a, 'gcx> HashStable> for ::mir::interpret::EvalError<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + self.kind.hash_stable(hcx, hasher) + } +} + +impl<'a, 'gcx> HashStable> +for ::mir::interpret::EvalErrorKind<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { 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), diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index fff555a8976c3..022b82841bcc2 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -1,4 +1,3 @@ -use std::error::Error; use std::{fmt, env}; use mir; @@ -30,7 +29,7 @@ impl<'tcx> From> 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>; -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()), } } } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index fe29222e883ce..a521caf4fdadb 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -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), } -#[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, // "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 { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3c4b9ae33519e..0b56dbda42c5e 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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(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) => diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 55137e2891123..92cea61bae5cf 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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>) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f81617a3795a7..bae91d064a5a6 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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, diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index a3798f3ed4c65..33c80ab22a3c4 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -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 diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index f6e9994b5da3f..d055c979d1162 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -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)); } } diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 5a815e0dc67ef..6e7a37c2228df 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -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, }; diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index aa80ee7af18fc..4f0e97f6e1abe 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -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!(), }; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 47b2f430bc70e..192ab6e17e76a 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -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; } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 7c854ef04b7ca..32cb6c72d589b 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -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); } }