1
Fork 0

Merge pull request #89 from solson/unkind-primval

Remove PrimValKind field from PrimVal.
This commit is contained in:
Scott Olson 2016-11-27 19:09:39 -08:00 committed by GitHub
commit 140b21e09c
7 changed files with 266 additions and 307 deletions

View file

@ -11,17 +11,24 @@ use rustc::ty::Ty;
use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::ast::{FloatTy, IntTy, UintTy};
impl<'a, 'tcx> EvalContext<'a, 'tcx> { 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::*; use primval::PrimValKind::*;
match val.kind { match kind {
F32 => self.cast_float(val.to_f32() as f64, ty), F32 => self.cast_float(val.to_f32() as f64, dest_ty),
F64 => self.cast_float(val.to_f64(), 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> { fn cast_int(&self, v: u64, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
use primval::PrimValKind::*;
use rustc::ty::TypeVariants::*; use rustc::ty::TypeVariants::*;
match ty.sty { match ty.sty {
TyBool if v == 0 => Ok(PrimVal::from_bool(false)), TyBool if v == 0 => Ok(PrimVal::from_bool(false)),
TyBool if v == 1 => Ok(PrimVal::from_bool(true)), TyBool if v == 1 => Ok(PrimVal::from_bool(true)),
TyBool => Err(EvalError::InvalidBool), TyBool => Err(EvalError::InvalidBool),
TyInt(IntTy::I8) => Ok(PrimVal::new(v as i64 as i8 as u64, I8)), 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, I16)), 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, I32)), 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, I64)), 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::U8) => Ok(PrimVal::new(v as u8 as u64)),
TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64, U16)), TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64)),
TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64, U32)), TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64)),
TyUint(UintTy::U64) => Ok(PrimVal::new(v, U64)), TyUint(UintTy::U64) => Ok(PrimVal::new(v)),
TyInt(IntTy::Is) => { TyInt(IntTy::Is) => {
let int_ty = self.tcx.sess.target.int_type; 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) if negative => Ok(PrimVal::from_f32(v as i64 as f32)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v 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)), TyChar => Err(EvalError::InvalidChar(v)),
TyRawPtr(_) => Ok(PrimVal::from_ptr(Pointer::from_int(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> { fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*; use rustc::ty::TypeVariants::*;
match ty.sty { match ty.sty {
TyRef(..) | TyRawPtr(_) => Ok(PrimVal::from_ptr(ptr)), TyRef(..) | TyRawPtr(_) | TyFnPtr(_) | TyInt(_) | TyUint(_) =>
TyFnPtr(_) => Ok(PrimVal::from_fn_ptr(ptr)), Ok(PrimVal::from_ptr(ptr)),
TyInt(_) | TyUint(_) => self.transmute_primval(PrimVal::from_ptr(ptr), ty),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))), _ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
} }
} }

View file

@ -222,16 +222,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
&self.stack &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> { fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
// FIXME: cache these allocs // FIXME: cache these allocs
let ptr = self.memory.allocate(s.len() as u64, 1)?; let ptr = self.memory.allocate(s.len() as u64, 1)?;
self.memory.write_bytes(ptr, s.as_bytes())?; self.memory.write_bytes(ptr, s.as_bytes())?;
self.memory.freeze(ptr.alloc_id)?; 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> { 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; use rustc_const_math::ConstFloat;
let primval = match *const_val { let primval = match *const_val {
Integral(const_int) => { Integral(const_int) => PrimVal::new(const_int.to_u64_unchecked()),
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)
}
Float(ConstFloat::F32(f)) => PrimVal::from_f32(f), Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
Float(ConstFloat::F64(f)) => PrimVal::from_f64(f), Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
@ -432,9 +408,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
left: &mir::Operand<'tcx>, left: &mir::Operand<'tcx>,
right: &mir::Operand<'tcx>, right: &mir::Operand<'tcx>,
) -> EvalResult<'tcx, (PrimVal, bool)> { ) -> EvalResult<'tcx, (PrimVal, bool)> {
let left_primval = self.eval_operand_to_primval(left)?; let left_ty = self.operand_ty(left);
let right_primval = self.eval_operand_to_primval(right)?; let right_ty = self.operand_ty(right);
primval::binary_op(op, left_primval, right_primval) 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 /// 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>, left: &mir::Operand<'tcx>,
right: &mir::Operand<'tcx>, right: &mir::Operand<'tcx>,
dest: Lvalue<'tcx>, dest: Lvalue<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, bool> { ) -> EvalResult<'tcx, bool> {
let (val, overflowed) = self.binop_with_overflow(op, left, right)?; let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
self.write_primval(dest, val)?; self.write_primval(dest, val, dest_ty)?;
Ok(overflowed) Ok(overflowed)
} }
@ -506,7 +487,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
BinaryOp(bin_op, ref left, ref right) => { BinaryOp(bin_op, ref left, ref right) => {
// ignore overflow bit, rustc inserts check branches for us // 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) => { CheckedBinaryOp(bin_op, ref left, ref right) => {
@ -515,7 +496,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
UnaryOp(un_op, ref operand) => { UnaryOp(un_op, ref operand) => {
let val = self.eval_operand_to_primval(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) => { Aggregate(ref kind, ref operands) => {
@ -571,9 +553,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let operand_ty = self.operand_ty(operand); let operand_ty = self.operand_ty(operand);
assert_eq!(self.type_size(operand_ty)?, Some(0)); assert_eq!(self.type_size(operand_ty)?, Some(0));
} }
let value_size = self.type_size(dest_ty)?.expect("pointer types are sized"); self.write_primval(dest, PrimVal::from_int(0), dest_ty)?;
let zero = PrimVal::from_int_with_size(0, value_size);
self.write_primval(dest, zero)?;
} }
} else { } else {
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind); 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); assert_eq!(operands.len(), 0);
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
let n = adt_def.variants[variant].disr_val.to_u64_unchecked(); let n = adt_def.variants[variant].disr_val.to_u64_unchecked();
let size = discr.size().bytes(); self.write_primval(dest, PrimVal::new(n), dest_ty)?;
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)?;
} else { } else {
bug!("tried to assign {:?} to Layout::CEnum", kind); 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 src = self.eval_lvalue(lvalue)?;
let ty = self.lvalue_ty(lvalue); let ty = self.lvalue_ty(lvalue);
let (_, len) = src.elem_ty_and_len(ty); let (_, len) = src.elem_ty_and_len(ty);
let len_val = self.usize_primval(len); self.write_primval(dest, PrimVal::from_uint(len), dest_ty)?;
self.write_primval(dest, len_val)?;
} }
Ref(_, _, ref lvalue) => { Ref(_, _, ref lvalue) => {
@ -666,7 +637,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let val = match extra { let val = match extra {
LvalueExtra::None => Value::ByVal(ptr), 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::Vtable(vtable) => Value::ByValPair(ptr, PrimVal::from_ptr(vtable)),
LvalueExtra::DowncastVariant(..) => LvalueExtra::DowncastVariant(..) =>
bug!("attempted to take a reference to an enum downcast lvalue"), bug!("attempted to take a reference to an enum downcast lvalue"),
@ -677,7 +648,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Box(ty) => { Box(ty) => {
let ptr = self.alloc_ptr(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) => { Cast(kind, ref operand, cast_ty) => {
@ -707,7 +678,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
} else { } else {
let src_val = self.value_to_primval(src, src_ty)?; 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)?; 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) => { ty::TyFnDef(def_id, substs, fn_ty) => {
let fn_ty = self.tcx.erase_regions(&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); 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), 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 (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?;
let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty); 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); 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), 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 elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
let n_ptr = self.eval_operand(operand)?; let n_ptr = self.eval_operand(operand)?;
let usize = self.tcx.types.usize; let usize = self.tcx.types.usize;
let n = self.value_to_primval(n_ptr, usize)? let n = self.value_to_primval(n_ptr, usize)?.to_u64();
.expect_uint("Projection::Index expected usize");
assert!(n < len); assert!(n < len);
let ptr = base_ptr.offset(n * elem_size); let ptr = base_ptr.offset(n * elem_size);
(ptr, LvalueExtra::None) (ptr, LvalueExtra::None)
@ -1124,6 +1094,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Some(Value::ByRef(ptr)) => Lvalue::from_ptr(ptr), Some(Value::ByRef(ptr)) => Lvalue::from_ptr(ptr),
opt_val => { opt_val => {
let ty = self.stack[frame].mir.local_decls[local].ty; 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 substs = self.stack[frame].substs;
let ptr = self.alloc_ptr_with_substs(ty, substs)?; let ptr = self.alloc_ptr_with_substs(ty, substs)?;
self.stack[frame].set_local(local, Value::ByRef(ptr)); self.stack[frame].set_local(local, Value::ByRef(ptr));
@ -1168,7 +1139,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Value::ByVal(primval) => { Value::ByVal(primval) => {
let ptr = self.alloc_ptr(ty)?; 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) 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::ByRef(_) => bug!("follow_by_ref_value can't result in `ByRef`"),
Value::ByVal(primval) => { Value::ByVal(primval) => {
let new_primval = self.transmute_primval(primval, ty)?; self.ensure_valid_value(primval, ty)?;
self.ensure_valid_value(new_primval, ty)?; Ok(primval)
Ok(new_primval)
} }
Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"), 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( fn write_primval(
&mut self, &mut self,
dest: Lvalue<'tcx>, dest: Lvalue<'tcx>,
val: PrimVal, val: PrimVal,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, ()> { ) -> EvalResult<'tcx, ()> {
match dest { match dest {
Lvalue::Ptr { ptr, extra } => { Lvalue::Ptr { ptr, extra } => {
assert_eq!(extra, LvalueExtra::None); 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 } => { Lvalue::Local { frame, local } => {
self.stack[frame].set_local(local, Value::ByVal(val)); self.stack[frame].set_local(local, Value::ByVal(val));
@ -1319,7 +1288,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
) -> EvalResult<'tcx, ()> { ) -> EvalResult<'tcx, ()> {
match value { match value {
Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty), 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), 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); assert_eq!(self.get_field_count(ty)?, 2);
let field_0 = self.get_field_offset(ty, 0)?.bytes(); let field_0 = self.get_field_offset(ty, 0)?.bytes();
let field_1 = self.get_field_offset(ty, 1)?.bytes(); let field_1 = self.get_field_offset(ty, 1)?.bytes();
self.memory.write_primval(ptr.offset(field_0), a)?; let field_0_ty = self.get_field_ty(ty, 0)?;
self.memory.write_primval(ptr.offset(field_1), b)?; 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(()) Ok(())
} }
@ -1381,17 +1357,30 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::TyAdt(..) => { ty::TyAdt(..) => {
use rustc::ty::layout::Layout::*; use rustc::ty::layout::Layout::*;
if let CEnum { discr, signed, .. } = *self.type_layout(ty)? { match *self.type_layout(ty)? {
let size = discr.size().bytes(); CEnum { discr, signed, .. } => {
if signed { let size = discr.size().bytes();
PrimValKind::from_int_size(size) if signed {
} else { PrimValKind::from_int_size(size)
PrimValKind::from_uint_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)), _ => return Err(EvalError::TypeNotPrimitive(ty)),
}; };
@ -1432,8 +1421,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
I64 => 8, I64 => 8,
Is => self.memory.pointer_size(), Is => self.memory.pointer_size(),
}; };
let n = self.memory.read_int(ptr, size)?; PrimVal::from_int(self.memory.read_int(ptr, size)?)
PrimVal::from_int_with_size(n, size)
} }
ty::TyUint(uint_ty) => { ty::TyUint(uint_ty) => {
@ -1445,17 +1433,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
U64 => 8, U64 => 8,
Us => self.memory.pointer_size(), Us => self.memory.pointer_size(),
}; };
let n = self.memory.read_uint(ptr, size)?; PrimVal::from_uint(self.memory.read_uint(ptr, size)?)
PrimVal::from_uint_with_size(n, size)
} }
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?), ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(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) => { 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::TyBox(ty) |
ty::TyRef(_, ty::TypeAndMut { ty, .. }) | ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
ty::TyRawPtr(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 { let extra = match self.tcx.struct_tail(ty).sty {
ty::TyTrait(..) => PrimVal::from_ptr(self.memory.read_ptr(extra)?), ty::TyTrait(..) => PrimVal::from_ptr(self.memory.read_ptr(extra)?),
ty::TySlice(..) | 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), _ => bug!("unsized primval ptr read from {:?}", ty),
}; };
return Ok(Value::ByValPair(PrimVal::from_ptr(p), extra)); 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)? { if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
let size = discr.size().bytes(); let size = discr.size().bytes();
if signed { if signed {
let n = self.memory.read_int(ptr, size)?; PrimVal::from_int(self.memory.read_int(ptr, size)?)
PrimVal::from_int_with_size(n, size)
} else { } else {
let n = self.memory.read_uint(ptr, size)?; PrimVal::from_uint(self.memory.read_uint(ptr, size)?)
PrimVal::from_uint_with_size(n, size)
} }
} else { } else {
bug!("primitive read of non-clike enum: {:?}", ty); 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) { match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
(&ty::TyArray(_, length), &ty::TySlice(_)) => { (&ty::TyArray(_, length), &ty::TySlice(_)) => {
let ptr = src.read_ptr(&self.memory)?; 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); let ptr = PrimVal::from_ptr(ptr);
self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)?; self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)?;
} }

View file

@ -44,10 +44,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"arith_offset" => { "arith_offset" => {
let ptr = arg_vals[0].read_ptr(&self.memory)?; let ptr = arg_vals[0].read_ptr(&self.memory)?;
let offset = self.value_to_primval(arg_vals[1], isize)? let offset = self.value_to_primval(arg_vals[1], isize)?.to_i64();
.expect_int("arith_offset second arg not isize");
let new_ptr = ptr.signed_offset(offset); 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" => { "assume" => {
@ -85,8 +84,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Value::ByRef(_) => bug!("just read the value, can't be byref"), Value::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
}; };
self.write_primval(dest, old)?; self.write_primval(dest, old, ty)?;
self.write_primval(Lvalue::from_ptr(ptr), change)?; self.write_primval(Lvalue::from_ptr(ptr), change, ty)?;
} }
"atomic_cxchg" => { "atomic_cxchg" => {
@ -100,10 +99,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Value::ByRef(_) => bug!("just read the value, can't be byref"), Value::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), 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(); let dest = self.force_allocation(dest)?.to_ptr();
self.write_pair_to_ptr(old, val, dest, dest_ty)?; 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" => { "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::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_xadd_relaxed doesn't work with nonprimitives"), 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? // FIXME: what do atomics do on overflow?
let (val, _) = primval::binary_op(mir::BinOp::Add, old, change)?; let (val, _) = primval::binary_op(mir::BinOp::Add, old, kind, change, kind)?;
self.write_primval(Lvalue::from_ptr(ptr), val)?; self.write_primval(Lvalue::from_ptr(ptr), val, ty)?;
}, },
"atomic_xsub_rel" => { "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::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_xsub_rel doesn't work with nonprimitives"), 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? // FIXME: what do atomics do on overflow?
let (val, _) = primval::binary_op(mir::BinOp::Sub, old, change)?; let (val, _) = primval::binary_op(mir::BinOp::Sub, old, kind, change, kind)?;
self.write_primval(Lvalue::from_ptr(ptr), val)?; self.write_primval(Lvalue::from_ptr(ptr), val, ty)?;
} }
"breakpoint" => unimplemented!(), // halt miri "breakpoint" => unimplemented!(), // halt miri
@ -148,8 +150,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let elem_align = self.type_align(elem_ty)?; let elem_align = self.type_align(elem_ty)?;
let src = arg_vals[0].read_ptr(&self.memory)?; let src = arg_vals[0].read_ptr(&self.memory)?;
let dest = arg_vals[1].read_ptr(&self.memory)?; let dest = arg_vals[1].read_ptr(&self.memory)?;
let count = self.value_to_primval(arg_vals[2], usize)? let count = self.value_to_primval(arg_vals[2], usize)?.to_u64();
.expect_uint("arith_offset second arg not isize");
self.memory.copy(src, dest, count * elem_size, elem_align)?; self.memory.copy(src, dest, count * elem_size, elem_align)?;
} }
@ -157,17 +158,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"cttz" | "cttz" |
"ctlz" | "ctlz" |
"bswap" => { "bswap" => {
let elem_ty = substs.type_at(0); let ty = substs.type_at(0);
let num = self.value_to_primval(arg_vals[0], elem_ty)?; let num = self.value_to_primval(arg_vals[0], ty)?;
let num = numeric_intrinsic(intrinsic_name, num); let kind = self.ty_to_primval_kind(ty)?;
self.write_primval(dest, num)?; let num = numeric_intrinsic(intrinsic_name, num, kind);
self.write_primval(dest, num, ty)?;
} }
"discriminant_value" => { "discriminant_value" => {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let adt_ptr = arg_vals[0].read_ptr(&self.memory)?; let adt_ptr = arg_vals[0].read_ptr(&self.memory)?;
let discr_val = self.read_discriminant_value(adt_ptr, ty)?; 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" => { "drop_in_place" => {
@ -196,23 +198,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
"fabsf32" => { "fabsf32" => {
let f = self.value_to_primval(arg_vals[2], f32)? let f = self.value_to_primval(arg_vals[2], f32)?.to_f32();
.expect_f32("fabsf32 read non f32"); self.write_primval(dest, PrimVal::from_f32(f.abs()), dest_ty)?;
self.write_primval(dest, PrimVal::from_f32(f.abs()))?;
} }
"fabsf64" => { "fabsf64" => {
let f = self.value_to_primval(arg_vals[2], f64)? let f = self.value_to_primval(arg_vals[2], f64)?.to_f64();
.expect_f64("fabsf64 read non f64"); self.write_primval(dest, PrimVal::from_f64(f.abs()), dest_ty)?;
self.write_primval(dest, PrimVal::from_f64(f.abs()))?;
} }
"fadd_fast" => { "fadd_fast" => {
let ty = substs.type_at(0); 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 a = self.value_to_primval(arg_vals[0], ty)?;
let b = 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)?; let result = primval::binary_op(mir::BinOp::Add, a, kind, b, kind)?;
self.write_primval(dest, result.0)?; self.write_primval(dest, result.0, dest_ty)?;
} }
"likely" | "likely" |
@ -220,27 +221,26 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"forget" => {} "forget" => {}
"init" => { "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<Value>| { let init = |this: &mut Self, val: Option<Value>| {
match val { let zero_val = match val {
Some(Value::ByRef(ptr)) => { Some(Value::ByRef(ptr)) => {
this.memory.write_repeat(ptr, 0, size)?; this.memory.write_repeat(ptr, 0, size)?;
Ok(Some(Value::ByRef(ptr))) Value::ByRef(ptr)
}, },
None => match this.ty_to_primval_kind(dest_ty) { 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(_) => { Err(_) => {
let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?; let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?;
this.memory.write_repeat(ptr, 0, size)?; 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::ByVal(_)) => Value::ByVal(PrimVal::new(0)),
Some(Value::ByValPair(a, b)) => Ok(Some(Value::ByValPair( Some(Value::ByValPair(..)) =>
PrimVal::new(0, a.kind), Value::ByValPair(PrimVal::new(0), PrimVal::new(0)),
PrimVal::new(0, b.kind), };
))), Ok(Some(zero_val))
}
}; };
match dest { match dest {
Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?, Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
@ -253,16 +253,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"min_align_of" => { "min_align_of" => {
let elem_ty = substs.type_at(0); let elem_ty = substs.type_at(0);
let elem_align = self.type_align(elem_ty)?; let elem_align = self.type_align(elem_ty)?;
let align_val = self.usize_primval(elem_align as u64); let align_val = PrimVal::from_uint(elem_align as u64);
self.write_primval(dest, align_val)?; self.write_primval(dest, align_val, dest_ty)?;
} }
"pref_align_of" => { "pref_align_of" => {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let layout = self.type_layout(ty)?; let layout = self.type_layout(ty)?;
let align = layout.align(&self.tcx.data_layout).pref(); let align = layout.align(&self.tcx.data_layout).pref();
let align_val = self.usize_primval(align); let align_val = PrimVal::from_uint(align);
self.write_primval(dest, align_val)?; self.write_primval(dest, align_val, dest_ty)?;
} }
"move_val_init" => { "move_val_init" => {
@ -275,59 +275,52 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let env = self.tcx.empty_parameter_environment(); let env = self.tcx.empty_parameter_environment();
let needs_drop = self.tcx.type_needs_drop_given_env(ty, &env); 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" => { "offset" => {
let pointee_ty = substs.type_at(0); let pointee_ty = substs.type_at(0);
// FIXME: assuming here that type size is < i64::max_value() // 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 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)? let offset = self.value_to_primval(arg_vals[1], isize)?.to_i64();
.expect_int("offset second arg not isize");
let ptr = arg_vals[0].read_ptr(&self.memory)?; let ptr = arg_vals[0].read_ptr(&self.memory)?;
let result_ptr = ptr.signed_offset(offset * pointee_size); 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" => { "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" => { "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" => { "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" => { "powif32" => {
let f = self.value_to_primval(arg_vals[0], f32)? let f = self.value_to_primval(arg_vals[0], f32)?.to_f32();
.expect_f32("powif32 first arg not f32"); let i = self.value_to_primval(arg_vals[1], i32)?.to_i64();
let i = self.value_to_primval(arg_vals[1], i32)? self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)), dest_ty)?;
.expect_int("powif32 second arg not i32");
self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)))?;
} }
"powif64" => { "powif64" => {
let f = self.value_to_primval(arg_vals[0], f64)? let f = self.value_to_primval(arg_vals[0], f64)?.to_f64();
.expect_f64("powif64 first arg not f64"); let i = self.value_to_primval(arg_vals[1], i32)?.to_i64();
let i = self.value_to_primval(arg_vals[1], i32)? self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)), dest_ty)?;
.expect_int("powif64 second arg not i32");
self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)))?;
} }
"sqrtf32" => { "sqrtf32" => {
let f = self.value_to_primval(arg_vals[0], f32)? let f = self.value_to_primval(arg_vals[0], f32)?.to_f32();
.expect_f32("sqrtf32 first arg not f32"); self.write_primval(dest, PrimVal::from_f32(f.sqrt()), dest_ty)?;
self.write_primval(dest, PrimVal::from_f32(f.sqrt()))?;
} }
"sqrtf64" => { "sqrtf64" => {
let f = self.value_to_primval(arg_vals[0], f64)? let f = self.value_to_primval(arg_vals[0], f64)?.to_f64();
.expect_f64("sqrtf64 first arg not f64"); self.write_primval(dest, PrimVal::from_f64(f.sqrt()), dest_ty)?;
self.write_primval(dest, PrimVal::from_f64(f.sqrt()))?;
} }
"size_of" => { "size_of" => {
@ -337,23 +330,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// .expect("size_of intrinsic called on unsized value") // .expect("size_of intrinsic called on unsized value")
// see https://github.com/rust-lang/rust/pull/37708 // see https://github.com/rust-lang/rust/pull/37708
let size = self.type_size(ty)?.unwrap_or(!0) as u64; let size = self.type_size(ty)?.unwrap_or(!0) as u64;
let size_val = self.usize_primval(size); self.write_primval(dest, PrimVal::from_uint(size), dest_ty)?;
self.write_primval(dest, size_val)?;
} }
"size_of_val" => { "size_of_val" => {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?; let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?;
let size_val = self.usize_primval(size); self.write_primval(dest, PrimVal::from_uint(size), dest_ty)?;
self.write_primval(dest, size_val)?;
} }
"min_align_of_val" | "min_align_of_val" |
"align_of_val" => { "align_of_val" => {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let (_, align) = self.size_and_align_of_dst(ty, arg_vals[0])?; let (_, align) = self.size_and_align_of_dst(ty, arg_vals[0])?;
let align_val = self.usize_primval(align); self.write_primval(dest, PrimVal::from_uint(align), dest_ty)?;
self.write_primval(dest, align_val)?;
} }
"type_name" => { "type_name" => {
@ -365,17 +355,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"type_id" => { "type_id" => {
let ty = substs.type_at(0); let ty = substs.type_at(0);
let n = self.tcx.type_id_hash(ty); 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" => { "transmute" => {
let dest_ty = substs.type_at(1); let dest_ty = substs.type_at(1);
let val = match arg_vals[0] { self.write_value(arg_vals[0], dest, dest_ty)?;
Value::ByVal(primval) =>
Value::ByVal(self.transmute_primval(primval, dest_ty)?),
v => v,
};
self.write_value(val, dest, dest_ty)?;
} }
"uninit" => { "uninit" => {
@ -511,11 +496,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
macro_rules! integer_intrinsic { macro_rules! integer_intrinsic {
($name:expr, $val:expr, $method:ident) => ({ ($name:expr, $val:expr, $kind:expr, $method:ident) => ({
let val = $val; let val = $val;
use primval::PrimValKind::*; use primval::PrimValKind::*;
let bits = match val.kind { let bits = match $kind {
I8 => (val.bits as i8).$method() as u64, I8 => (val.bits as i8).$method() as u64,
U8 => (val.bits as u8).$method() as u64, U8 => (val.bits as u8).$method() as u64,
I16 => (val.bits as i16).$method() as u64, I16 => (val.bits as i16).$method() as u64,
@ -527,16 +512,16 @@ macro_rules! integer_intrinsic {
_ => bug!("invalid `{}` argument: {:?}", $name, val), _ => 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 { match name {
"bswap" => integer_intrinsic!("bswap", val, swap_bytes), "bswap" => integer_intrinsic!("bswap", val, kind, swap_bytes),
"ctlz" => integer_intrinsic!("ctlz", val, leading_zeros), "ctlz" => integer_intrinsic!("ctlz", val, kind, leading_zeros),
"ctpop" => integer_intrinsic!("ctpop", val, count_ones), "ctpop" => integer_intrinsic!("ctpop", val, kind, count_ones),
"cttz" => integer_intrinsic!("cttz", val, trailing_zeros), "cttz" => integer_intrinsic!("cttz", val, kind, trailing_zeros),
_ => bug!("not a numeric intrinsic: {}", name), _ => bug!("not a numeric intrinsic: {}", name),
} }
} }

View file

@ -100,7 +100,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
terminator.source_info.span)? 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 { return match *msg {
mir::AssertMessage::BoundsCheck { ref len, ref index } => { mir::AssertMessage::BoundsCheck { ref len, ref index } => {
let span = terminator.source_info.span; let span = terminator.source_info.span;
let len = self.eval_operand_to_primval(len).expect("can't eval len") let len = self.eval_operand_to_primval(len)
.expect_uint("BoundsCheck len wasn't a uint"); .expect("can't eval len")
.to_u64();
let index = self.eval_operand_to_primval(index) let index = self.eval_operand_to_primval(index)
.expect("can't eval index") .expect("can't eval index")
.expect_uint("BoundsCheck index wasn't a uint"); .to_u64();
Err(EvalError::ArrayIndexOutOfBounds(span, len, index)) Err(EvalError::ArrayIndexOutOfBounds(span, len, index))
}, },
mir::AssertMessage::Math(ref err) => mir::AssertMessage::Math(ref err) =>
@ -194,9 +198,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Abi::C => { Abi::C => {
let ty = fn_ty.sig.0.output; 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(); 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); self.goto_block(target);
Ok(()) Ok(())
} }
@ -303,7 +306,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
def_id: DefId, def_id: DefId,
args: &[mir::Operand<'tcx>], args: &[mir::Operand<'tcx>],
dest: Lvalue<'tcx>, dest: Lvalue<'tcx>,
dest_size: u64, dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, ()> { ) -> EvalResult<'tcx, ()> {
let name = self.tcx.item_name(def_id); let name = self.tcx.item_name(def_id);
let attrs = self.tcx.get_attrs(def_id); let attrs = self.tcx.get_attrs(def_id);
@ -325,36 +328,32 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match &link_name[..] { match &link_name[..] {
"__rust_allocate" => { "__rust_allocate" => {
let size = self.value_to_primval(args[0], usize)? let size = self.value_to_primval(args[0], usize)?.to_u64();
.expect_uint("__rust_allocate first arg not usize"); let align = self.value_to_primval(args[1], usize)?.to_u64();
let align = self.value_to_primval(args[1], usize)?
.expect_uint("__rust_allocate second arg not usize");
let ptr = self.memory.allocate(size, align)?; 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" => { "__rust_deallocate" => {
let ptr = args[0].read_ptr(&self.memory)?; let ptr = args[0].read_ptr(&self.memory)?;
// FIXME: insert sanity check for size and align? // FIXME: insert sanity check for size and align?
let _old_size = self.value_to_primval(args[1], usize)? let _old_size = self.value_to_primval(args[1], usize)?.to_u64();
.expect_uint("__rust_deallocate second arg not usize"); let _align = self.value_to_primval(args[2], usize)?.to_u64();
let _align = self.value_to_primval(args[2], usize)?
.expect_uint("__rust_deallocate third arg not usize");
self.memory.deallocate(ptr)?; self.memory.deallocate(ptr)?;
}, },
"__rust_reallocate" => { "__rust_reallocate" => {
let ptr = args[0].read_ptr(&self.memory)?; 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 size = self.value_to_primval(args[2], usize)?.to_u64();
let align = self.value_to_primval(args[3], usize)?.expect_uint("__rust_reallocate fourth arg not usize"); let align = self.value_to_primval(args[3], usize)?.to_u64();
let new_ptr = self.memory.reallocate(ptr, size, align)?; 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" => { "memcmp" => {
let left = args[0].read_ptr(&self.memory)?; let left = args[0].read_ptr(&self.memory)?;
let right = args[1].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 result = {
let left_bytes = self.memory.read_bytes(left, n)?; 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)?;
} }
_ => { _ => {

View file

@ -11,7 +11,7 @@ use rustc::ty::layout::{self, TargetDataLayout};
use syntax::abi::Abi; use syntax::abi::Abi;
use error::{EvalError, EvalResult}; use error::{EvalError, EvalResult};
use primval::PrimVal; use primval::{PrimVal, PrimValKind};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Allocations and pointers // Allocations and pointers
@ -559,13 +559,18 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
Ok(()) 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 { if let Some(alloc_id) = val.relocation {
return self.write_ptr(dest, Pointer::new(alloc_id, val.bits)); return self.write_ptr(dest, Pointer::new(alloc_id, val.bits));
} }
use primval::PrimValKind::*; use primval::PrimValKind::*;
let (size, bits) = match val.kind { let (size, bits) = match kind {
I8 | U8 | Bool => (1, val.bits as u8 as u64), I8 | U8 | Bool => (1, val.bits as u8 as u64),
I16 | U16 => (2, val.bits as u16 as u64), I16 | U16 => (2, val.bits as u16 as u64),
I32 | U32 | F32 | Char => (4, val.bits as u32 as u64), I32 | U32 | F32 | Char => (4, val.bits as u32 as u64),

View file

@ -38,11 +38,6 @@ pub struct PrimVal {
/// `Allocation` in the `memory` module has a list of relocations, but a `PrimVal` is only /// `Allocation` in the `memory` module has a list of relocations, but a `PrimVal` is only
/// large enough to contain one, hence the `Option`. /// large enough to contain one, hence the `Option`.
pub relocation: Option<AllocId>, pub relocation: Option<AllocId>,
// 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)] #[derive(Clone, Copy, Debug, PartialEq)]
@ -87,44 +82,40 @@ impl PrimValKind {
} }
impl PrimVal { impl PrimVal {
pub fn new(bits: u64, kind: PrimValKind) -> Self { pub fn new(bits: u64) -> Self {
PrimVal { bits: bits, relocation: None, kind: kind } PrimVal { bits: bits, relocation: None }
} }
pub fn new_with_relocation(bits: u64, kind: PrimValKind, alloc_id: AllocId) -> Self { pub fn new_with_relocation(bits: u64, alloc_id: AllocId) -> Self {
PrimVal { bits: bits, relocation: Some(alloc_id), kind: kind } PrimVal { bits: bits, relocation: Some(alloc_id) }
} }
pub fn from_ptr(ptr: Pointer) -> Self { pub fn from_ptr(ptr: Pointer) -> Self {
PrimVal::new_with_relocation(ptr.offset as u64, PrimValKind::Ptr, ptr.alloc_id) PrimVal::new_with_relocation(ptr.offset as u64, ptr.alloc_id)
}
pub fn from_fn_ptr(ptr: Pointer) -> Self {
PrimVal::new_with_relocation(ptr.offset as u64, PrimValKind::FnPtr, ptr.alloc_id)
} }
pub fn from_bool(b: bool) -> Self { 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 { 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 { 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 { 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 { pub fn from_uint(n: u64) -> Self {
PrimVal::new(n, PrimValKind::from_uint_size(size)) PrimVal::new(n)
} }
pub fn from_int_with_size(n: i64, size: u64) -> Self { pub fn from_int(n: i64) -> Self {
PrimVal::new(n as u64, PrimValKind::from_int_size(size)) PrimVal::new(n as u64)
} }
pub fn to_f32(self) -> f32 { pub fn to_f32(self) -> f32 {
@ -144,31 +135,27 @@ impl PrimVal {
} }
pub fn try_as_uint<'tcx>(self) -> EvalResult<'tcx, u64> { 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 { pub fn to_u64(self) -> u64 {
if let Ok(int) = self.try_as_uint() { if let Some(ptr) = self.try_as_ptr() {
return int; return ptr.to_int().expect("non abstract ptr") as u64;
}
use self::PrimValKind::*;
match self.kind {
U8 | U16 | U32 | U64 => self.bits,
_ => bug!("{}", error_msg),
} }
self.bits
} }
pub fn expect_int(self, error_msg: &str) -> i64 { pub fn to_i64(self) -> i64 {
if let Ok(int) = self.try_as_uint() { if let Some(ptr) = self.try_as_ptr() {
return int as i64; return ptr.to_int().expect("non abstract ptr") as i64;
} }
self.bits as i64
}
use self::PrimValKind::*; pub fn try_as_ptr(self) -> Option<Pointer> {
match self.kind { self.relocation.map(|alloc_id| {
I8 | I16 | I32 | I64 => self.bits as i64, Pointer::new(alloc_id, self.bits)
_ => bug!("{}", error_msg), })
}
} }
pub fn try_as_bool<'tcx>(self) -> EvalResult<'tcx, bool> { 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 { macro_rules! overflow {
($kind:expr, $op:ident, $l:expr, $r:expr) => ({ ($op:ident, $l:expr, $r:expr) => ({
let (val, overflowed) = $l.$op($r); let (val, overflowed) = $l.$op($r);
let primval = PrimVal::new(val as u64, $kind); let primval = PrimVal::new(val as u64);
Ok((primval, overflowed)) Ok((primval, overflowed))
}) })
} }
@ -211,14 +185,14 @@ macro_rules! int_arithmetic {
let l = $l; let l = $l;
let r = $r; let r = $r;
match $kind { match $kind {
I8 => overflow!(I8, $int_op, l as i8, r as i8), I8 => overflow!($int_op, l as i8, r as i8),
I16 => overflow!(I16, $int_op, l as i16, r as i16), I16 => overflow!($int_op, l as i16, r as i16),
I32 => overflow!(I32, $int_op, l as i32, r as i32), I32 => overflow!($int_op, l as i32, r as i32),
I64 => overflow!(I64, $int_op, l as i64, r as i64), I64 => overflow!($int_op, l as i64, r as i64),
U8 => overflow!(U8, $int_op, l as u8, r as u8), U8 => overflow!($int_op, l as u8, r as u8),
U16 => overflow!(U16, $int_op, l as u16, r as u16), U16 => overflow!($int_op, l as u16, r as u16),
U32 => overflow!(U32, $int_op, l as u32, r as u32), U32 => overflow!($int_op, l as u32, r as u32),
U64 => overflow!(U64, $int_op, l as u64, r as u64), U64 => overflow!($int_op, l as u64, r as u64),
_ => bug!("int_arithmetic should only be called on int primvals"), _ => bug!("int_arithmetic should only be called on int primvals"),
} }
}) })
@ -229,37 +203,37 @@ macro_rules! int_shift {
let l = $l; let l = $l;
let r = $r; let r = $r;
match $kind { match $kind {
I8 => overflow!(I8, $int_op, l as i8, r), I8 => overflow!($int_op, l as i8, r),
I16 => overflow!(I16, $int_op, l as i16, r), I16 => overflow!($int_op, l as i16, r),
I32 => overflow!(I32, $int_op, l as i32, r), I32 => overflow!($int_op, l as i32, r),
I64 => overflow!(I64, $int_op, l as i64, r), I64 => overflow!($int_op, l as i64, r),
U8 => overflow!(U8, $int_op, l as u8, r), U8 => overflow!($int_op, l as u8, r),
U16 => overflow!(U16, $int_op, l as u16, r), U16 => overflow!($int_op, l as u16, r),
U32 => overflow!(U32, $int_op, l as u32, r), U32 => overflow!($int_op, l as u32, r),
U64 => overflow!(U64, $int_op, l as u64, r), U64 => overflow!($int_op, l as u64, r),
_ => bug!("int_shift should only be called on int primvals"), _ => bug!("int_shift should only be called on int primvals"),
} }
}) })
} }
macro_rules! float_arithmetic { 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 l = $from_bits($l);
let r = $from_bits($r); let r = $from_bits($r);
let bits = $to_bits(l $float_op r); let bits = $to_bits(l $float_op r);
PrimVal::new(bits, $kind) PrimVal::new(bits)
}) })
} }
macro_rules! f32_arithmetic { macro_rules! f32_arithmetic {
($float_op:tt, $l:expr, $r:expr) => ( ($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 { macro_rules! f64_arithmetic {
($float_op:tt, $l:expr, $r:expr) => ( ($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>( pub fn binary_op<'tcx>(
bin_op: mir::BinOp, bin_op: mir::BinOp,
left: PrimVal, left: PrimVal,
right: PrimVal left_kind: PrimValKind,
right: PrimVal,
right_kind: PrimValKind,
) -> EvalResult<'tcx, (PrimVal, bool)> { ) -> EvalResult<'tcx, (PrimVal, bool)> {
use rustc::mir::BinOp::*; use rustc::mir::BinOp::*;
use self::PrimValKind::*; 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 // 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 // can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in
// that range. // that range.
let type_bits: u32 = match left.kind { let type_bits: u32 = match left_kind {
I8 | U8 => 8, I8 | U8 => 8,
I16 | U16 => 16, I16 | U16 => 16,
I32 | U32 => 32, I32 | U32 => 32,
@ -301,18 +277,18 @@ pub fn binary_op<'tcx>(
let r = (right.bits as u32) & (type_bits - 1); let r = (right.bits as u32) & (type_bits - 1);
return match bin_op { return match bin_op {
Shl => int_shift!(left.kind, overflowing_shl, l, r), Shl => int_shift!(left_kind, overflowing_shl, l, r),
Shr => int_shift!(left.kind, overflowing_shr, l, r), Shr => int_shift!(left_kind, overflowing_shr, l, r),
_ => bug!("it has already been checked that this is a shift op"), _ => 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); let msg = format!("unimplemented binary op: {:?}, {:?}, {:?}", left, right, bin_op);
return Err(EvalError::Unimplemented(msg)); 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)), (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)), (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)), (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), (Gt, _) => PrimVal::from_bool(l > r),
(Ge, _) => PrimVal::from_bool(l >= r), (Ge, _) => PrimVal::from_bool(l >= r),
(BitOr, k) => PrimVal::new(l | r, k), (BitOr, _) => PrimVal::new(l | r),
(BitAnd, k) => PrimVal::new(l & r, k), (BitAnd, _) => PrimVal::new(l & r),
(BitXor, k) => PrimVal::new(l ^ r, k), (BitXor, _) => PrimVal::new(l ^ r),
(Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, 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), (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 rustc::mir::UnOp::*;
use self::PrimValKind::*; 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, Bool) => !bits_to_bool(val.bits) as u64,
(Not, U8) => !(val.bits as u8) 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))
} }

View file

@ -61,8 +61,6 @@ fn compile_test() {
let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") { let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
Box::new(files.chain(std::fs::read_dir(path).unwrap())) Box::new(files.chain(std::fs::read_dir(path).unwrap()))
} else { } 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) Box::new(files)
}; };
let mut mir_not_found = 0; let mut mir_not_found = 0;