diff --git a/src/interpreter/cast.rs b/src/interpreter/cast.rs index 5bf5d26c228..7a0285da440 100644 --- a/src/interpreter/cast.rs +++ b/src/interpreter/cast.rs @@ -11,17 +11,24 @@ use rustc::ty::Ty; use syntax::ast::{FloatTy, IntTy, UintTy}; impl<'a, 'tcx> EvalContext<'a, 'tcx> { - pub(super) fn cast_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { + pub(super) fn cast_primval( + &self, + val: PrimVal, + src_ty: Ty<'tcx>, + dest_ty: Ty<'tcx> + ) -> EvalResult<'tcx, PrimVal> { + let kind = self.ty_to_primval_kind(src_ty)?; + use primval::PrimValKind::*; - match val.kind { - F32 => self.cast_float(val.to_f32() as f64, ty), - F64 => self.cast_float(val.to_f64(), ty), + match kind { + F32 => self.cast_float(val.to_f32() as f64, dest_ty), + F64 => self.cast_float(val.to_f64(), dest_ty), - I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits as i64, ty), + I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits as i64, dest_ty), - Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false), + Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, dest_ty, false), - FnPtr | Ptr => self.cast_ptr(val.to_ptr(), ty), + FnPtr | Ptr => self.cast_ptr(val.to_ptr(), dest_ty), } } @@ -30,22 +37,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } fn cast_int(&self, v: u64, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> { - use primval::PrimValKind::*; use rustc::ty::TypeVariants::*; match ty.sty { TyBool if v == 0 => Ok(PrimVal::from_bool(false)), TyBool if v == 1 => Ok(PrimVal::from_bool(true)), TyBool => Err(EvalError::InvalidBool), - TyInt(IntTy::I8) => Ok(PrimVal::new(v as i64 as i8 as u64, I8)), - TyInt(IntTy::I16) => Ok(PrimVal::new(v as i64 as i16 as u64, I16)), - TyInt(IntTy::I32) => Ok(PrimVal::new(v as i64 as i32 as u64, I32)), - TyInt(IntTy::I64) => Ok(PrimVal::new(v as i64 as i64 as u64, I64)), + TyInt(IntTy::I8) => Ok(PrimVal::new(v as i64 as i8 as u64)), + TyInt(IntTy::I16) => Ok(PrimVal::new(v as i64 as i16 as u64)), + TyInt(IntTy::I32) => Ok(PrimVal::new(v as i64 as i32 as u64)), + TyInt(IntTy::I64) => Ok(PrimVal::new(v as i64 as i64 as u64)), - TyUint(UintTy::U8) => Ok(PrimVal::new(v as u8 as u64, U8)), - TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64, U16)), - TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64, U32)), - TyUint(UintTy::U64) => Ok(PrimVal::new(v, U64)), + TyUint(UintTy::U8) => Ok(PrimVal::new(v as u8 as u64)), + TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64)), + TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64)), + TyUint(UintTy::U64) => Ok(PrimVal::new(v)), TyInt(IntTy::Is) => { let int_ty = self.tcx.sess.target.int_type; @@ -64,7 +70,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i64 as f32)), TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)), - TyChar if v as u8 as u64 == v => Ok(PrimVal::new(v, Char)), + TyChar if v as u8 as u64 == v => Ok(PrimVal::new(v)), TyChar => Err(EvalError::InvalidChar(v)), TyRawPtr(_) => Ok(PrimVal::from_ptr(Pointer::from_int(v))), @@ -91,9 +97,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { use rustc::ty::TypeVariants::*; match ty.sty { - TyRef(..) | TyRawPtr(_) => Ok(PrimVal::from_ptr(ptr)), - TyFnPtr(_) => Ok(PrimVal::from_fn_ptr(ptr)), - TyInt(_) | TyUint(_) => self.transmute_primval(PrimVal::from_ptr(ptr), ty), + TyRef(..) | TyRawPtr(_) | TyFnPtr(_) | TyInt(_) | TyUint(_) => + Ok(PrimVal::from_ptr(ptr)), _ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))), } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 59b3db7aa82..63d3029e311 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -222,16 +222,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { &self.stack } - fn usize_primval(&self, n: u64) -> PrimVal { - PrimVal::from_uint_with_size(n, self.memory.pointer_size()) - } - fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> { // FIXME: cache these allocs let ptr = self.memory.allocate(s.len() as u64, 1)?; self.memory.write_bytes(ptr, s.as_bytes())?; self.memory.freeze(ptr.alloc_id)?; - Ok(Value::ByValPair(PrimVal::from_ptr(ptr), self.usize_primval(s.len() as u64))) + Ok(Value::ByValPair(PrimVal::from_ptr(ptr), PrimVal::from_uint(s.len() as u64))) } fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> { @@ -239,27 +235,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { use rustc_const_math::ConstFloat; let primval = match *const_val { - Integral(const_int) => { - use rustc_const_math::ConstInt::*; - use rustc_const_math::ConstIsize::*; - use rustc_const_math::ConstUsize::*; - - let kind = match const_int { - I8(_) => PrimValKind::I8, - I16(_) | Isize(Is16(_)) => PrimValKind::I16, - I32(_) | Isize(Is32(_)) => PrimValKind::I32, - I64(_) | Isize(Is64(_)) => PrimValKind::I64, - U8(_) => PrimValKind::U8, - U16(_) | Usize(Us16(_)) => PrimValKind::U16, - U32(_) | Usize(Us32(_)) => PrimValKind::U32, - U64(_) | Usize(Us64(_)) => PrimValKind::U64, - - Infer(_) | InferSigned(_) => - bug!("uninferred constants only exist before typeck"), - }; - - PrimVal::new(const_int.to_u64_unchecked(), kind) - } + Integral(const_int) => PrimVal::new(const_int.to_u64_unchecked()), Float(ConstFloat::F32(f)) => PrimVal::from_f32(f), Float(ConstFloat::F64(f)) => PrimVal::from_f64(f), @@ -432,9 +408,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { left: &mir::Operand<'tcx>, right: &mir::Operand<'tcx>, ) -> EvalResult<'tcx, (PrimVal, bool)> { - let left_primval = self.eval_operand_to_primval(left)?; - let right_primval = self.eval_operand_to_primval(right)?; - primval::binary_op(op, left_primval, right_primval) + let left_ty = self.operand_ty(left); + let right_ty = self.operand_ty(right); + let left_kind = self.ty_to_primval_kind(left_ty)?; + let right_kind = self.ty_to_primval_kind(right_ty)?; + let left_val = self.eval_operand_to_primval(left)?; + let right_val = self.eval_operand_to_primval(right)?; + primval::binary_op(op, left_val, left_kind, right_val, right_kind) } /// Applies the binary operation `op` to the two operands and writes a tuple of the result @@ -460,9 +440,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { left: &mir::Operand<'tcx>, right: &mir::Operand<'tcx>, dest: Lvalue<'tcx>, + dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx, bool> { let (val, overflowed) = self.binop_with_overflow(op, left, right)?; - self.write_primval(dest, val)?; + self.write_primval(dest, val, dest_ty)?; Ok(overflowed) } @@ -506,7 +487,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { BinaryOp(bin_op, ref left, ref right) => { // ignore overflow bit, rustc inserts check branches for us - self.intrinsic_overflowing(bin_op, left, right, dest)?; + self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?; } CheckedBinaryOp(bin_op, ref left, ref right) => { @@ -515,7 +496,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { UnaryOp(un_op, ref operand) => { let val = self.eval_operand_to_primval(operand)?; - self.write_primval(dest, primval::unary_op(un_op, val)?)?; + let kind = self.ty_to_primval_kind(dest_ty)?; + self.write_primval(dest, primval::unary_op(un_op, val, kind)?, dest_ty)?; } Aggregate(ref kind, ref operands) => { @@ -571,9 +553,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let operand_ty = self.operand_ty(operand); assert_eq!(self.type_size(operand_ty)?, Some(0)); } - let value_size = self.type_size(dest_ty)?.expect("pointer types are sized"); - let zero = PrimVal::from_int_with_size(0, value_size); - self.write_primval(dest, zero)?; + self.write_primval(dest, PrimVal::from_int(0), dest_ty)?; } } else { bug!("tried to assign {:?} to Layout::RawNullablePointer", kind); @@ -604,19 +584,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } - CEnum { discr, signed, .. } => { + CEnum { .. } => { assert_eq!(operands.len(), 0); if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { let n = adt_def.variants[variant].disr_val.to_u64_unchecked(); - let size = discr.size().bytes(); - - let val = if signed { - PrimVal::from_int_with_size(n as i64, size) - } else { - PrimVal::from_uint_with_size(n, size) - }; - - self.write_primval(dest, val)?; + self.write_primval(dest, PrimVal::new(n), dest_ty)?; } else { bug!("tried to assign {:?} to Layout::CEnum", kind); } @@ -655,8 +627,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let src = self.eval_lvalue(lvalue)?; let ty = self.lvalue_ty(lvalue); let (_, len) = src.elem_ty_and_len(ty); - let len_val = self.usize_primval(len); - self.write_primval(dest, len_val)?; + self.write_primval(dest, PrimVal::from_uint(len), dest_ty)?; } Ref(_, _, ref lvalue) => { @@ -666,7 +637,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let val = match extra { LvalueExtra::None => Value::ByVal(ptr), - LvalueExtra::Length(len) => Value::ByValPair(ptr, self.usize_primval(len)), + LvalueExtra::Length(len) => Value::ByValPair(ptr, PrimVal::from_uint(len)), LvalueExtra::Vtable(vtable) => Value::ByValPair(ptr, PrimVal::from_ptr(vtable)), LvalueExtra::DowncastVariant(..) => bug!("attempted to take a reference to an enum downcast lvalue"), @@ -677,7 +648,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Box(ty) => { let ptr = self.alloc_ptr(ty)?; - self.write_primval(dest, PrimVal::from_ptr(ptr))?; + self.write_primval(dest, PrimVal::from_ptr(ptr), dest_ty)?; } Cast(kind, ref operand, cast_ty) => { @@ -707,7 +678,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } else { let src_val = self.value_to_primval(src, src_ty)?; - let dest_val = self.cast_primval(src_val, dest_ty)?; + let dest_val = self.cast_primval(src_val, src_ty, dest_ty)?; self.write_value(Value::ByVal(dest_val), dest, dest_ty)?; } } @@ -716,7 +687,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty::TyFnDef(def_id, substs, fn_ty) => { let fn_ty = self.tcx.erase_regions(&fn_ty); let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty); - self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?; + self.write_value(Value::ByVal(PrimVal::from_ptr(fn_ptr)), dest, dest_ty)?; }, ref other => bug!("reify fn pointer on {:?}", other), }, @@ -728,7 +699,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?; let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty); let fn_ptr = self.memory.create_fn_ptr(self.tcx, def_id, substs, unsafe_fn_ty); - self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?; + self.write_value(Value::ByVal(PrimVal::from_ptr(fn_ptr)), dest, dest_ty)?; }, ref other => bug!("fn to unsafe fn cast on {:?}", other), }, @@ -1059,8 +1030,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized"); let n_ptr = self.eval_operand(operand)?; let usize = self.tcx.types.usize; - let n = self.value_to_primval(n_ptr, usize)? - .expect_uint("Projection::Index expected usize"); + let n = self.value_to_primval(n_ptr, usize)?.to_u64(); assert!(n < len); let ptr = base_ptr.offset(n * elem_size); (ptr, LvalueExtra::None) @@ -1124,6 +1094,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Some(Value::ByRef(ptr)) => Lvalue::from_ptr(ptr), opt_val => { let ty = self.stack[frame].mir.local_decls[local].ty; + let ty = self.monomorphize(ty, self.stack[frame].substs); let substs = self.stack[frame].substs; let ptr = self.alloc_ptr_with_substs(ty, substs)?; self.stack[frame].set_local(local, Value::ByRef(ptr)); @@ -1168,7 +1139,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByVal(primval) => { let ptr = self.alloc_ptr(ty)?; - self.memory.write_primval(ptr, primval)?; + let kind = self.ty_to_primval_kind(ty)?; + self.memory.write_primval(ptr, primval, kind)?; Ok(ptr) } @@ -1193,28 +1165,25 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByRef(_) => bug!("follow_by_ref_value can't result in `ByRef`"), Value::ByVal(primval) => { - let new_primval = self.transmute_primval(primval, ty)?; - self.ensure_valid_value(new_primval, ty)?; - Ok(new_primval) + self.ensure_valid_value(primval, ty)?; + Ok(primval) } Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"), } } - fn transmute_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - Ok(PrimVal { kind: self.ty_to_primval_kind(ty)?, ..val }) - } - fn write_primval( &mut self, dest: Lvalue<'tcx>, val: PrimVal, + dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx, ()> { match dest { Lvalue::Ptr { ptr, extra } => { assert_eq!(extra, LvalueExtra::None); - self.memory.write_primval(ptr, val) + let kind = self.ty_to_primval_kind(dest_ty)?; + self.memory.write_primval(ptr, val, kind) } Lvalue::Local { frame, local } => { self.stack[frame].set_local(local, Value::ByVal(val)); @@ -1319,7 +1288,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ) -> EvalResult<'tcx, ()> { match value { Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty), - Value::ByVal(primval) => self.memory.write_primval(dest, primval), + Value::ByVal(primval) => { + let kind = self.ty_to_primval_kind(dest_ty)?; + self.memory.write_primval(dest, primval, kind) + } Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest, dest_ty), } } @@ -1334,8 +1306,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { assert_eq!(self.get_field_count(ty)?, 2); let field_0 = self.get_field_offset(ty, 0)?.bytes(); let field_1 = self.get_field_offset(ty, 1)?.bytes(); - self.memory.write_primval(ptr.offset(field_0), a)?; - self.memory.write_primval(ptr.offset(field_1), b)?; + let field_0_ty = self.get_field_ty(ty, 0)?; + let field_1_ty = self.get_field_ty(ty, 1)?; + let field_0_kind = self.ty_to_primval_kind(field_0_ty)?; + let field_1_kind = self.ty_to_primval_kind(field_1_ty)?; + self.memory.write_primval(ptr.offset(field_0), a, field_0_kind)?; + self.memory.write_primval(ptr.offset(field_1), b, field_1_kind)?; Ok(()) } @@ -1381,17 +1357,30 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty::TyAdt(..) => { use rustc::ty::layout::Layout::*; - if let CEnum { discr, signed, .. } = *self.type_layout(ty)? { - let size = discr.size().bytes(); - if signed { - PrimValKind::from_int_size(size) - } else { - PrimValKind::from_uint_size(size) + match *self.type_layout(ty)? { + CEnum { discr, signed, .. } => { + let size = discr.size().bytes(); + if signed { + PrimValKind::from_int_size(size) + } else { + PrimValKind::from_uint_size(size) + } } - } else { - return Err(EvalError::TypeNotPrimitive(ty)); + + RawNullablePointer { value, .. } => { + use rustc::ty::layout::Primitive::*; + match value { + // TODO(solson): Does signedness matter here? What should the sign be? + Int(int) => PrimValKind::from_uint_size(int.size().bytes()), + F32 => PrimValKind::F32, + F64 => PrimValKind::F64, + Pointer => PrimValKind::Ptr, + } + } + + _ => return Err(EvalError::TypeNotPrimitive(ty)), } - }, + } _ => return Err(EvalError::TypeNotPrimitive(ty)), }; @@ -1432,8 +1421,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { I64 => 8, Is => self.memory.pointer_size(), }; - let n = self.memory.read_int(ptr, size)?; - PrimVal::from_int_with_size(n, size) + PrimVal::from_int(self.memory.read_int(ptr, size)?) } ty::TyUint(uint_ty) => { @@ -1445,17 +1433,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { U64 => 8, Us => self.memory.pointer_size(), }; - let n = self.memory.read_uint(ptr, size)?; - PrimVal::from_uint_with_size(n, size) + PrimVal::from_uint(self.memory.read_uint(ptr, size)?) } ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?), ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?), + // TODO(solson): Should this even be here? Fn items aren't primvals, are they? ty::TyFnDef(def_id, substs, fn_ty) => { - PrimVal::from_fn_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty)) + PrimVal::from_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty)) }, - ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_fn_ptr)?, + + ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_ptr)?, ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut { ty, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { @@ -1468,7 +1457,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let extra = match self.tcx.struct_tail(ty).sty { ty::TyTrait(..) => PrimVal::from_ptr(self.memory.read_ptr(extra)?), ty::TySlice(..) | - ty::TyStr => self.usize_primval(self.memory.read_usize(extra)?), + ty::TyStr => PrimVal::from_uint(self.memory.read_usize(extra)?), _ => bug!("unsized primval ptr read from {:?}", ty), }; return Ok(Value::ByValPair(PrimVal::from_ptr(p), extra)); @@ -1480,11 +1469,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { if let CEnum { discr, signed, .. } = *self.type_layout(ty)? { let size = discr.size().bytes(); if signed { - let n = self.memory.read_int(ptr, size)?; - PrimVal::from_int_with_size(n, size) + PrimVal::from_int(self.memory.read_int(ptr, size)?) } else { - let n = self.memory.read_uint(ptr, size)?; - PrimVal::from_uint_with_size(n, size) + PrimVal::from_uint(self.memory.read_uint(ptr, size)?) } } else { bug!("primitive read of non-clike enum: {:?}", ty); @@ -1531,7 +1518,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match (&src_pointee_ty.sty, &dest_pointee_ty.sty) { (&ty::TyArray(_, length), &ty::TySlice(_)) => { let ptr = src.read_ptr(&self.memory)?; - let len = self.usize_primval(length as u64); + let len = PrimVal::from_uint(length as u64); let ptr = PrimVal::from_ptr(ptr); self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)?; } diff --git a/src/interpreter/terminator/intrinsics.rs b/src/interpreter/terminator/intrinsics.rs index 87a9229aba0..16cdffe24ce 100644 --- a/src/interpreter/terminator/intrinsics.rs +++ b/src/interpreter/terminator/intrinsics.rs @@ -44,10 +44,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "arith_offset" => { let ptr = arg_vals[0].read_ptr(&self.memory)?; - let offset = self.value_to_primval(arg_vals[1], isize)? - .expect_int("arith_offset second arg not isize"); + let offset = self.value_to_primval(arg_vals[1], isize)?.to_i64(); let new_ptr = ptr.signed_offset(offset); - self.write_primval(dest, PrimVal::from_ptr(new_ptr))?; + self.write_primval(dest, PrimVal::from_ptr(new_ptr), dest_ty)?; } "assume" => { @@ -85,8 +84,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByRef(_) => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; - self.write_primval(dest, old)?; - self.write_primval(Lvalue::from_ptr(ptr), change)?; + self.write_primval(dest, old, ty)?; + self.write_primval(Lvalue::from_ptr(ptr), change, ty)?; } "atomic_cxchg" => { @@ -100,10 +99,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByRef(_) => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; - let (val, _) = primval::binary_op(mir::BinOp::Eq, old, expect_old)?; + let kind = self.ty_to_primval_kind(ty)?; + let (val, _) = primval::binary_op(mir::BinOp::Eq, old, kind, expect_old, kind)?; let dest = self.force_allocation(dest)?.to_ptr(); self.write_pair_to_ptr(old, val, dest, dest_ty)?; - self.write_primval(Lvalue::from_ptr(ptr), change)?; + self.write_primval(Lvalue::from_ptr(ptr), change, ty)?; } "atomic_xadd_relaxed" => { @@ -116,10 +116,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByRef(_) => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_xadd_relaxed doesn't work with nonprimitives"), }; - self.write_primval(dest, old)?; + self.write_primval(dest, old, ty)?; + let kind = self.ty_to_primval_kind(ty)?; // FIXME: what do atomics do on overflow? - let (val, _) = primval::binary_op(mir::BinOp::Add, old, change)?; - self.write_primval(Lvalue::from_ptr(ptr), val)?; + let (val, _) = primval::binary_op(mir::BinOp::Add, old, kind, change, kind)?; + self.write_primval(Lvalue::from_ptr(ptr), val, ty)?; }, "atomic_xsub_rel" => { @@ -132,10 +133,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByRef(_) => bug!("just read the value, can't be byref"), Value::ByValPair(..) => bug!("atomic_xsub_rel doesn't work with nonprimitives"), }; - self.write_primval(dest, old)?; + self.write_primval(dest, old, ty)?; + let kind = self.ty_to_primval_kind(ty)?; // FIXME: what do atomics do on overflow? - let (val, _) = primval::binary_op(mir::BinOp::Sub, old, change)?; - self.write_primval(Lvalue::from_ptr(ptr), val)?; + let (val, _) = primval::binary_op(mir::BinOp::Sub, old, kind, change, kind)?; + self.write_primval(Lvalue::from_ptr(ptr), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -148,8 +150,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let elem_align = self.type_align(elem_ty)?; let src = arg_vals[0].read_ptr(&self.memory)?; let dest = arg_vals[1].read_ptr(&self.memory)?; - let count = self.value_to_primval(arg_vals[2], usize)? - .expect_uint("arith_offset second arg not isize"); + let count = self.value_to_primval(arg_vals[2], usize)?.to_u64(); self.memory.copy(src, dest, count * elem_size, elem_align)?; } @@ -157,17 +158,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "cttz" | "ctlz" | "bswap" => { - let elem_ty = substs.type_at(0); - let num = self.value_to_primval(arg_vals[0], elem_ty)?; - let num = numeric_intrinsic(intrinsic_name, num); - self.write_primval(dest, num)?; + let ty = substs.type_at(0); + let num = self.value_to_primval(arg_vals[0], ty)?; + let kind = self.ty_to_primval_kind(ty)?; + let num = numeric_intrinsic(intrinsic_name, num, kind); + self.write_primval(dest, num, ty)?; } "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = arg_vals[0].read_ptr(&self.memory)?; let discr_val = self.read_discriminant_value(adt_ptr, ty)?; - self.write_primval(dest, PrimVal::new(discr_val, PrimValKind::U64))?; + self.write_primval(dest, PrimVal::new(discr_val), dest_ty)?; } "drop_in_place" => { @@ -196,23 +198,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "fabsf32" => { - let f = self.value_to_primval(arg_vals[2], f32)? - .expect_f32("fabsf32 read non f32"); - self.write_primval(dest, PrimVal::from_f32(f.abs()))?; + let f = self.value_to_primval(arg_vals[2], f32)?.to_f32(); + self.write_primval(dest, PrimVal::from_f32(f.abs()), dest_ty)?; } "fabsf64" => { - let f = self.value_to_primval(arg_vals[2], f64)? - .expect_f64("fabsf64 read non f64"); - self.write_primval(dest, PrimVal::from_f64(f.abs()))?; + let f = self.value_to_primval(arg_vals[2], f64)?.to_f64(); + self.write_primval(dest, PrimVal::from_f64(f.abs()), dest_ty)?; } "fadd_fast" => { let ty = substs.type_at(0); + let kind = self.ty_to_primval_kind(ty)?; let a = self.value_to_primval(arg_vals[0], ty)?; let b = self.value_to_primval(arg_vals[0], ty)?; - let result = primval::binary_op(mir::BinOp::Add, a, b)?; - self.write_primval(dest, result.0)?; + let result = primval::binary_op(mir::BinOp::Add, a, kind, b, kind)?; + self.write_primval(dest, result.0, dest_ty)?; } "likely" | @@ -220,27 +221,26 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "forget" => {} "init" => { - let size = dest_layout.size(&self.tcx.data_layout).bytes(); + let size = self.type_size(dest_ty)?.expect("cannot zero unsized value");; let init = |this: &mut Self, val: Option| { - match val { + let zero_val = match val { Some(Value::ByRef(ptr)) => { this.memory.write_repeat(ptr, 0, size)?; - Ok(Some(Value::ByRef(ptr))) + Value::ByRef(ptr) }, None => match this.ty_to_primval_kind(dest_ty) { - Ok(kind) => Ok(Some(Value::ByVal(PrimVal::new(0, kind)))), + Ok(_) => Value::ByVal(PrimVal::new(0)), Err(_) => { let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?; this.memory.write_repeat(ptr, 0, size)?; - Ok(Some(Value::ByRef(ptr))) + Value::ByRef(ptr) } }, - Some(Value::ByVal(value)) => Ok(Some(Value::ByVal(PrimVal::new(0, value.kind)))), - Some(Value::ByValPair(a, b)) => Ok(Some(Value::ByValPair( - PrimVal::new(0, a.kind), - PrimVal::new(0, b.kind), - ))), - } + Some(Value::ByVal(_)) => Value::ByVal(PrimVal::new(0)), + Some(Value::ByValPair(..)) => + Value::ByValPair(PrimVal::new(0), PrimVal::new(0)), + }; + Ok(Some(zero_val)) }; match dest { Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?, @@ -253,16 +253,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.type_align(elem_ty)?; - let align_val = self.usize_primval(elem_align as u64); - self.write_primval(dest, align_val)?; + let align_val = PrimVal::from_uint(elem_align as u64); + self.write_primval(dest, align_val, dest_ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.type_layout(ty)?; let align = layout.align(&self.tcx.data_layout).pref(); - let align_val = self.usize_primval(align); - self.write_primval(dest, align_val)?; + let align_val = PrimVal::from_uint(align); + self.write_primval(dest, align_val, dest_ty)?; } "move_val_init" => { @@ -275,59 +275,52 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let ty = substs.type_at(0); let env = self.tcx.empty_parameter_environment(); let needs_drop = self.tcx.type_needs_drop_given_env(ty, &env); - self.write_primval(dest, PrimVal::from_bool(needs_drop))?; + self.write_primval(dest, PrimVal::from_bool(needs_drop), dest_ty)?; } "offset" => { let pointee_ty = substs.type_at(0); // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64; - let offset = self.value_to_primval(arg_vals[1], isize)? - .expect_int("offset second arg not isize"); + let offset = self.value_to_primval(arg_vals[1], isize)?.to_i64(); let ptr = arg_vals[0].read_ptr(&self.memory)?; let result_ptr = ptr.signed_offset(offset * pointee_size); - self.write_primval(dest, PrimVal::from_ptr(result_ptr))?; + self.write_primval(dest, PrimVal::from_ptr(result_ptr), dest_ty)?; } "overflowing_sub" => { - self.intrinsic_overflowing(mir::BinOp::Sub, &args[0], &args[1], dest)?; + self.intrinsic_overflowing(mir::BinOp::Sub, &args[0], &args[1], dest, dest_ty)?; } "overflowing_mul" => { - self.intrinsic_overflowing(mir::BinOp::Mul, &args[0], &args[1], dest)?; + self.intrinsic_overflowing(mir::BinOp::Mul, &args[0], &args[1], dest, dest_ty)?; } "overflowing_add" => { - self.intrinsic_overflowing(mir::BinOp::Add, &args[0], &args[1], dest)?; + self.intrinsic_overflowing(mir::BinOp::Add, &args[0], &args[1], dest, dest_ty)?; } "powif32" => { - let f = self.value_to_primval(arg_vals[0], f32)? - .expect_f32("powif32 first arg not f32"); - let i = self.value_to_primval(arg_vals[1], i32)? - .expect_int("powif32 second arg not i32"); - self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)))?; + let f = self.value_to_primval(arg_vals[0], f32)?.to_f32(); + let i = self.value_to_primval(arg_vals[1], i32)?.to_i64(); + self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)), dest_ty)?; } "powif64" => { - let f = self.value_to_primval(arg_vals[0], f64)? - .expect_f64("powif64 first arg not f64"); - let i = self.value_to_primval(arg_vals[1], i32)? - .expect_int("powif64 second arg not i32"); - self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)))?; + let f = self.value_to_primval(arg_vals[0], f64)?.to_f64(); + let i = self.value_to_primval(arg_vals[1], i32)?.to_i64(); + self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)), dest_ty)?; } "sqrtf32" => { - let f = self.value_to_primval(arg_vals[0], f32)? - .expect_f32("sqrtf32 first arg not f32"); - self.write_primval(dest, PrimVal::from_f32(f.sqrt()))?; + let f = self.value_to_primval(arg_vals[0], f32)?.to_f32(); + self.write_primval(dest, PrimVal::from_f32(f.sqrt()), dest_ty)?; } "sqrtf64" => { - let f = self.value_to_primval(arg_vals[0], f64)? - .expect_f64("sqrtf64 first arg not f64"); - self.write_primval(dest, PrimVal::from_f64(f.sqrt()))?; + let f = self.value_to_primval(arg_vals[0], f64)?.to_f64(); + self.write_primval(dest, PrimVal::from_f64(f.sqrt()), dest_ty)?; } "size_of" => { @@ -337,23 +330,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // .expect("size_of intrinsic called on unsized value") // see https://github.com/rust-lang/rust/pull/37708 let size = self.type_size(ty)?.unwrap_or(!0) as u64; - let size_val = self.usize_primval(size); - self.write_primval(dest, size_val)?; + self.write_primval(dest, PrimVal::from_uint(size), dest_ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?; - let size_val = self.usize_primval(size); - self.write_primval(dest, size_val)?; + self.write_primval(dest, PrimVal::from_uint(size), dest_ty)?; } "min_align_of_val" | "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, arg_vals[0])?; - let align_val = self.usize_primval(align); - self.write_primval(dest, align_val)?; + self.write_primval(dest, PrimVal::from_uint(align), dest_ty)?; } "type_name" => { @@ -365,17 +355,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::new(n, PrimValKind::U64))?; + self.write_primval(dest, PrimVal::new(n), dest_ty)?; } "transmute" => { let dest_ty = substs.type_at(1); - let val = match arg_vals[0] { - Value::ByVal(primval) => - Value::ByVal(self.transmute_primval(primval, dest_ty)?), - v => v, - }; - self.write_value(val, dest, dest_ty)?; + self.write_value(arg_vals[0], dest, dest_ty)?; } "uninit" => { @@ -511,11 +496,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } macro_rules! integer_intrinsic { - ($name:expr, $val:expr, $method:ident) => ({ + ($name:expr, $val:expr, $kind:expr, $method:ident) => ({ let val = $val; use primval::PrimValKind::*; - let bits = match val.kind { + let bits = match $kind { I8 => (val.bits as i8).$method() as u64, U8 => (val.bits as u8).$method() as u64, I16 => (val.bits as i16).$method() as u64, @@ -527,16 +512,16 @@ macro_rules! integer_intrinsic { _ => bug!("invalid `{}` argument: {:?}", $name, val), }; - PrimVal::new(bits, val.kind) + PrimVal::new(bits) }); } -fn numeric_intrinsic(name: &str, val: PrimVal) -> PrimVal { +fn numeric_intrinsic(name: &str, val: PrimVal, kind: PrimValKind) -> PrimVal { match name { - "bswap" => integer_intrinsic!("bswap", val, swap_bytes), - "ctlz" => integer_intrinsic!("ctlz", val, leading_zeros), - "ctpop" => integer_intrinsic!("ctpop", val, count_ones), - "cttz" => integer_intrinsic!("cttz", val, trailing_zeros), + "bswap" => integer_intrinsic!("bswap", val, kind, swap_bytes), + "ctlz" => integer_intrinsic!("ctlz", val, kind, leading_zeros), + "ctpop" => integer_intrinsic!("ctpop", val, kind, count_ones), + "cttz" => integer_intrinsic!("cttz", val, kind, trailing_zeros), _ => bug!("not a numeric intrinsic: {}", name), } } diff --git a/src/interpreter/terminator/mod.rs b/src/interpreter/terminator/mod.rs index 8f58105de4b..a346b8fafa5 100644 --- a/src/interpreter/terminator/mod.rs +++ b/src/interpreter/terminator/mod.rs @@ -100,7 +100,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { terminator.source_info.span)? } - _ => return Err(EvalError::Unimplemented(format!("can't handle callee of type {:?}", func_ty))), + _ => { + let msg = format!("can't handle callee of type {:?}", func_ty); + return Err(EvalError::Unimplemented(msg)); + } } } @@ -126,11 +129,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { return match *msg { mir::AssertMessage::BoundsCheck { ref len, ref index } => { let span = terminator.source_info.span; - let len = self.eval_operand_to_primval(len).expect("can't eval len") - .expect_uint("BoundsCheck len wasn't a uint"); + let len = self.eval_operand_to_primval(len) + .expect("can't eval len") + .to_u64(); let index = self.eval_operand_to_primval(index) .expect("can't eval index") - .expect_uint("BoundsCheck index wasn't a uint"); + .to_u64(); Err(EvalError::ArrayIndexOutOfBounds(span, len, index)) }, mir::AssertMessage::Math(ref err) => @@ -194,9 +198,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Abi::C => { let ty = fn_ty.sig.0.output; - let size = self.type_size(ty)?.expect("function return type cannot be unsized"); let (ret, target) = destination.unwrap(); - self.call_c_abi(def_id, arg_operands, ret, size)?; + self.call_c_abi(def_id, arg_operands, ret, ty)?; self.goto_block(target); Ok(()) } @@ -303,7 +306,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { def_id: DefId, args: &[mir::Operand<'tcx>], dest: Lvalue<'tcx>, - dest_size: u64, + dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx, ()> { let name = self.tcx.item_name(def_id); let attrs = self.tcx.get_attrs(def_id); @@ -325,36 +328,32 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match &link_name[..] { "__rust_allocate" => { - let size = self.value_to_primval(args[0], usize)? - .expect_uint("__rust_allocate first arg not usize"); - let align = self.value_to_primval(args[1], usize)? - .expect_uint("__rust_allocate second arg not usize"); + let size = self.value_to_primval(args[0], usize)?.to_u64(); + let align = self.value_to_primval(args[1], usize)?.to_u64(); let ptr = self.memory.allocate(size, align)?; - self.write_primval(dest, PrimVal::from_ptr(ptr))?; + self.write_primval(dest, PrimVal::from_ptr(ptr), dest_ty)?; } "__rust_deallocate" => { let ptr = args[0].read_ptr(&self.memory)?; // FIXME: insert sanity check for size and align? - let _old_size = self.value_to_primval(args[1], usize)? - .expect_uint("__rust_deallocate second arg not usize"); - let _align = self.value_to_primval(args[2], usize)? - .expect_uint("__rust_deallocate third arg not usize"); + let _old_size = self.value_to_primval(args[1], usize)?.to_u64(); + let _align = self.value_to_primval(args[2], usize)?.to_u64(); self.memory.deallocate(ptr)?; }, "__rust_reallocate" => { let ptr = args[0].read_ptr(&self.memory)?; - let size = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate third arg not usize"); - let align = self.value_to_primval(args[3], usize)?.expect_uint("__rust_reallocate fourth arg not usize"); + let size = self.value_to_primval(args[2], usize)?.to_u64(); + let align = self.value_to_primval(args[3], usize)?.to_u64(); let new_ptr = self.memory.reallocate(ptr, size, align)?; - self.write_primval(dest, PrimVal::from_ptr(new_ptr))?; + self.write_primval(dest, PrimVal::from_ptr(new_ptr), dest_ty)?; } "memcmp" => { let left = args[0].read_ptr(&self.memory)?; let right = args[1].read_ptr(&self.memory)?; - let n = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate first arg not usize"); + let n = self.value_to_primval(args[2], usize)?.to_u64(); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -368,7 +367,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } }; - self.write_primval(dest, PrimVal::from_int_with_size(result, dest_size))?; + self.write_primval(dest, PrimVal::new(result as u64), dest_ty)?; } _ => { diff --git a/src/memory.rs b/src/memory.rs index c4c045c121b..3d05300f0ab 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -11,7 +11,7 @@ use rustc::ty::layout::{self, TargetDataLayout}; use syntax::abi::Abi; use error::{EvalError, EvalResult}; -use primval::PrimVal; +use primval::{PrimVal, PrimValKind}; //////////////////////////////////////////////////////////////////////////////// // Allocations and pointers @@ -559,13 +559,18 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { Ok(()) } - pub fn write_primval(&mut self, dest: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> { + pub fn write_primval( + &mut self, + dest: Pointer, + val: PrimVal, + kind: PrimValKind, + ) -> EvalResult<'tcx, ()> { if let Some(alloc_id) = val.relocation { return self.write_ptr(dest, Pointer::new(alloc_id, val.bits)); } use primval::PrimValKind::*; - let (size, bits) = match val.kind { + let (size, bits) = match kind { I8 | U8 | Bool => (1, val.bits as u8 as u64), I16 | U16 => (2, val.bits as u16 as u64), I32 | U32 | F32 | Char => (4, val.bits as u32 as u64), diff --git a/src/primval.rs b/src/primval.rs index 20b08b5a0a1..83d9c18f34f 100644 --- a/src/primval.rs +++ b/src/primval.rs @@ -38,11 +38,6 @@ pub struct PrimVal { /// `Allocation` in the `memory` module has a list of relocations, but a `PrimVal` is only /// large enough to contain one, hence the `Option`. pub relocation: Option, - - // FIXME(solson): I think we can make this field unnecessary, or at least move it outside of - // this struct. We can either match over `Ty`s or generate simple `PrimVal`s from `Ty`s and - // match over those to decide which operations to perform on `PrimVal`s. - pub kind: PrimValKind, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -87,44 +82,40 @@ impl PrimValKind { } impl PrimVal { - pub fn new(bits: u64, kind: PrimValKind) -> Self { - PrimVal { bits: bits, relocation: None, kind: kind } + pub fn new(bits: u64) -> Self { + PrimVal { bits: bits, relocation: None } } - pub fn new_with_relocation(bits: u64, kind: PrimValKind, alloc_id: AllocId) -> Self { - PrimVal { bits: bits, relocation: Some(alloc_id), kind: kind } + pub fn new_with_relocation(bits: u64, alloc_id: AllocId) -> Self { + PrimVal { bits: bits, relocation: Some(alloc_id) } } pub fn from_ptr(ptr: Pointer) -> Self { - PrimVal::new_with_relocation(ptr.offset as u64, PrimValKind::Ptr, ptr.alloc_id) - } - - pub fn from_fn_ptr(ptr: Pointer) -> Self { - PrimVal::new_with_relocation(ptr.offset as u64, PrimValKind::FnPtr, ptr.alloc_id) + PrimVal::new_with_relocation(ptr.offset as u64, ptr.alloc_id) } pub fn from_bool(b: bool) -> Self { - PrimVal::new(b as u64, PrimValKind::Bool) + PrimVal::new(b as u64) } pub fn from_char(c: char) -> Self { - PrimVal::new(c as u64, PrimValKind::Char) + PrimVal::new(c as u64) } pub fn from_f32(f: f32) -> Self { - PrimVal::new(f32_to_bits(f), PrimValKind::F32) + PrimVal::new(f32_to_bits(f)) } pub fn from_f64(f: f64) -> Self { - PrimVal::new(f64_to_bits(f), PrimValKind::F64) + PrimVal::new(f64_to_bits(f)) } - pub fn from_uint_with_size(n: u64, size: u64) -> Self { - PrimVal::new(n, PrimValKind::from_uint_size(size)) + pub fn from_uint(n: u64) -> Self { + PrimVal::new(n) } - pub fn from_int_with_size(n: i64, size: u64) -> Self { - PrimVal::new(n as u64, PrimValKind::from_int_size(size)) + pub fn from_int(n: i64) -> Self { + PrimVal::new(n as u64) } pub fn to_f32(self) -> f32 { @@ -144,31 +135,27 @@ impl PrimVal { } pub fn try_as_uint<'tcx>(self) -> EvalResult<'tcx, u64> { - self.to_ptr().to_int().map(|val| val as u64) + self.to_ptr().to_int() } - pub fn expect_uint(self, error_msg: &str) -> u64 { - if let Ok(int) = self.try_as_uint() { - return int; - } - - use self::PrimValKind::*; - match self.kind { - U8 | U16 | U32 | U64 => self.bits, - _ => bug!("{}", error_msg), + pub fn to_u64(self) -> u64 { + if let Some(ptr) = self.try_as_ptr() { + return ptr.to_int().expect("non abstract ptr") as u64; } + self.bits } - pub fn expect_int(self, error_msg: &str) -> i64 { - if let Ok(int) = self.try_as_uint() { - return int as i64; + pub fn to_i64(self) -> i64 { + if let Some(ptr) = self.try_as_ptr() { + return ptr.to_int().expect("non abstract ptr") as i64; } + self.bits as i64 + } - use self::PrimValKind::*; - match self.kind { - I8 | I16 | I32 | I64 => self.bits as i64, - _ => bug!("{}", error_msg), - } + pub fn try_as_ptr(self) -> Option { + self.relocation.map(|alloc_id| { + Pointer::new(alloc_id, self.bits) + }) } pub fn try_as_bool<'tcx>(self) -> EvalResult<'tcx, bool> { @@ -179,19 +166,6 @@ impl PrimVal { } } - pub fn expect_f32(self, error_msg: &str) -> f32 { - match self.kind { - PrimValKind::F32 => bits_to_f32(self.bits), - _ => bug!("{}", error_msg), - } - } - - pub fn expect_f64(self, error_msg: &str) -> f64 { - match self.kind { - PrimValKind::F32 => bits_to_f64(self.bits), - _ => bug!("{}", error_msg), - } - } } //////////////////////////////////////////////////////////////////////////////// @@ -199,9 +173,9 @@ impl PrimVal { //////////////////////////////////////////////////////////////////////////////// macro_rules! overflow { - ($kind:expr, $op:ident, $l:expr, $r:expr) => ({ + ($op:ident, $l:expr, $r:expr) => ({ let (val, overflowed) = $l.$op($r); - let primval = PrimVal::new(val as u64, $kind); + let primval = PrimVal::new(val as u64); Ok((primval, overflowed)) }) } @@ -211,14 +185,14 @@ macro_rules! int_arithmetic { let l = $l; let r = $r; match $kind { - I8 => overflow!(I8, $int_op, l as i8, r as i8), - I16 => overflow!(I16, $int_op, l as i16, r as i16), - I32 => overflow!(I32, $int_op, l as i32, r as i32), - I64 => overflow!(I64, $int_op, l as i64, r as i64), - U8 => overflow!(U8, $int_op, l as u8, r as u8), - U16 => overflow!(U16, $int_op, l as u16, r as u16), - U32 => overflow!(U32, $int_op, l as u32, r as u32), - U64 => overflow!(U64, $int_op, l as u64, r as u64), + I8 => overflow!($int_op, l as i8, r as i8), + I16 => overflow!($int_op, l as i16, r as i16), + I32 => overflow!($int_op, l as i32, r as i32), + I64 => overflow!($int_op, l as i64, r as i64), + U8 => overflow!($int_op, l as u8, r as u8), + U16 => overflow!($int_op, l as u16, r as u16), + U32 => overflow!($int_op, l as u32, r as u32), + U64 => overflow!($int_op, l as u64, r as u64), _ => bug!("int_arithmetic should only be called on int primvals"), } }) @@ -229,37 +203,37 @@ macro_rules! int_shift { let l = $l; let r = $r; match $kind { - I8 => overflow!(I8, $int_op, l as i8, r), - I16 => overflow!(I16, $int_op, l as i16, r), - I32 => overflow!(I32, $int_op, l as i32, r), - I64 => overflow!(I64, $int_op, l as i64, r), - U8 => overflow!(U8, $int_op, l as u8, r), - U16 => overflow!(U16, $int_op, l as u16, r), - U32 => overflow!(U32, $int_op, l as u32, r), - U64 => overflow!(U64, $int_op, l as u64, r), + I8 => overflow!($int_op, l as i8, r), + I16 => overflow!($int_op, l as i16, r), + I32 => overflow!($int_op, l as i32, r), + I64 => overflow!($int_op, l as i64, r), + U8 => overflow!($int_op, l as u8, r), + U16 => overflow!($int_op, l as u16, r), + U32 => overflow!($int_op, l as u32, r), + U64 => overflow!($int_op, l as u64, r), _ => bug!("int_shift should only be called on int primvals"), } }) } macro_rules! float_arithmetic { - ($kind:expr, $from_bits:ident, $to_bits:ident, $float_op:tt, $l:expr, $r:expr) => ({ + ($from_bits:ident, $to_bits:ident, $float_op:tt, $l:expr, $r:expr) => ({ let l = $from_bits($l); let r = $from_bits($r); let bits = $to_bits(l $float_op r); - PrimVal::new(bits, $kind) + PrimVal::new(bits) }) } macro_rules! f32_arithmetic { ($float_op:tt, $l:expr, $r:expr) => ( - float_arithmetic!(F32, bits_to_f32, f32_to_bits, $float_op, $l, $r) + float_arithmetic!(bits_to_f32, f32_to_bits, $float_op, $l, $r) ) } macro_rules! f64_arithmetic { ($float_op:tt, $l:expr, $r:expr) => ( - float_arithmetic!(F64, bits_to_f64, f64_to_bits, $float_op, $l, $r) + float_arithmetic!(bits_to_f64, f64_to_bits, $float_op, $l, $r) ) } @@ -267,7 +241,9 @@ macro_rules! f64_arithmetic { pub fn binary_op<'tcx>( bin_op: mir::BinOp, left: PrimVal, - right: PrimVal + left_kind: PrimValKind, + right: PrimVal, + right_kind: PrimValKind, ) -> EvalResult<'tcx, (PrimVal, bool)> { use rustc::mir::BinOp::*; use self::PrimValKind::*; @@ -288,7 +264,7 @@ pub fn binary_op<'tcx>( // These are the maximum values a bitshift RHS could possibly have. For example, u16 // can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in // that range. - let type_bits: u32 = match left.kind { + let type_bits: u32 = match left_kind { I8 | U8 => 8, I16 | U16 => 16, I32 | U32 => 32, @@ -301,18 +277,18 @@ pub fn binary_op<'tcx>( let r = (right.bits as u32) & (type_bits - 1); return match bin_op { - Shl => int_shift!(left.kind, overflowing_shl, l, r), - Shr => int_shift!(left.kind, overflowing_shr, l, r), + Shl => int_shift!(left_kind, overflowing_shl, l, r), + Shr => int_shift!(left_kind, overflowing_shr, l, r), _ => bug!("it has already been checked that this is a shift op"), }; } - if left.kind != right.kind { + if left_kind != right_kind { let msg = format!("unimplemented binary op: {:?}, {:?}, {:?}", left, right, bin_op); return Err(EvalError::Unimplemented(msg)); } - let val = match (bin_op, left.kind) { + let val = match (bin_op, left_kind) { (Eq, F32) => PrimVal::from_bool(bits_to_f32(l) == bits_to_f32(r)), (Ne, F32) => PrimVal::from_bool(bits_to_f32(l) != bits_to_f32(r)), (Lt, F32) => PrimVal::from_bool(bits_to_f32(l) < bits_to_f32(r)), @@ -346,9 +322,9 @@ pub fn binary_op<'tcx>( (Gt, _) => PrimVal::from_bool(l > r), (Ge, _) => PrimVal::from_bool(l >= r), - (BitOr, k) => PrimVal::new(l | r, k), - (BitAnd, k) => PrimVal::new(l & r, k), - (BitXor, k) => PrimVal::new(l ^ r, k), + (BitOr, _) => PrimVal::new(l | r), + (BitAnd, _) => PrimVal::new(l & r), + (BitXor, _) => PrimVal::new(l ^ r), (Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, l, r), (Sub, k) if k.is_int() => return int_arithmetic!(k, overflowing_sub, l, r), @@ -378,11 +354,15 @@ fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp, left: Pointer, right: Pointer) -> } } -pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> { +pub fn unary_op<'tcx>( + un_op: mir::UnOp, + val: PrimVal, + val_kind: PrimValKind, +) -> EvalResult<'tcx, PrimVal> { use rustc::mir::UnOp::*; use self::PrimValKind::*; - let bits = match (un_op, val.kind) { + let bits = match (un_op, val_kind) { (Not, Bool) => !bits_to_bool(val.bits) as u64, (Not, U8) => !(val.bits as u8) as u64, @@ -409,5 +389,5 @@ pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVa } }; - Ok(PrimVal::new(bits, val.kind)) + Ok(PrimVal::new(bits)) } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 181f06ba1eb..1ee86a07b22 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -61,8 +61,6 @@ fn compile_test() { let files: Box> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") { Box::new(files.chain(std::fs::read_dir(path).unwrap())) } else { - // print traces only when not running on the rust run-pass test suite (since tracing is slow) - std::env::set_var("MIRI_LOG", "trace"); Box::new(files) }; let mut mir_not_found = 0;