Turn PrimVal into an enum including Undefined.

This is step 1 of a refactoring to fix #95. The `Undefined` variant is
so far unused and the old `bits` and `relocation` fields are emulated
with two new temporary methods. There should be no functional change due
to this commit.
This commit is contained in:
Scott Olson 2016-12-15 23:40:45 -08:00
parent 9674e507ca
commit b36a83171b
7 changed files with 132 additions and 120 deletions

View File

@ -20,9 +20,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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, dest_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, dest_ty, false),
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits(), dest_ty, false),
FnPtr | Ptr => self.cast_ptr(val.to_ptr(), dest_ty),
}
@ -39,15 +39,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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)),
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)),
TyInt(IntTy::I8) => Ok(PrimVal::Bytes(v as i64 as i8 as u64)),
TyInt(IntTy::I16) => Ok(PrimVal::Bytes(v as i64 as i16 as u64)),
TyInt(IntTy::I32) => Ok(PrimVal::Bytes(v as i64 as i32 as u64)),
TyInt(IntTy::I64) => Ok(PrimVal::Bytes(v as i64 as i64 as 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)),
TyUint(UintTy::U8) => Ok(PrimVal::Bytes(v as u8 as u64)),
TyUint(UintTy::U16) => Ok(PrimVal::Bytes(v as u16 as u64)),
TyUint(UintTy::U32) => Ok(PrimVal::Bytes(v as u32 as u64)),
TyUint(UintTy::U64) => Ok(PrimVal::Bytes(v)),
TyInt(IntTy::Is) => {
let int_ty = self.tcx.sess.target.int_type;
@ -66,10 +66,10 @@ 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)),
TyChar if v as u8 as u64 == v => Ok(PrimVal::Bytes(v)),
TyChar => Err(EvalError::InvalidChar(v)),
TyRawPtr(_) => Ok(PrimVal::from_ptr(Pointer::from_int(v))),
TyRawPtr(_) => Ok(PrimVal::Pointer(Pointer::from_int(v))),
_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
}
@ -94,7 +94,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
use rustc::ty::TypeVariants::*;
match ty.sty {
TyRef(..) | TyRawPtr(_) | TyFnPtr(_) | TyInt(_) | TyUint(_) =>
Ok(PrimVal::from_ptr(ptr)),
Ok(PrimVal::Pointer(ptr)),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
}
}

View File

@ -172,7 +172,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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), PrimVal::from_uint(s.len() as u64)))
Ok(Value::ByValPair(PrimVal::Pointer(ptr), PrimVal::from_uint(s.len() as u64)))
}
pub(super) fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
@ -180,7 +180,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
use rustc_const_math::ConstFloat;
let primval = match *const_val {
Integral(const_int) => PrimVal::new(const_int.to_u64_unchecked()),
Integral(const_int) => PrimVal::Bytes(const_int.to_u64_unchecked()),
Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
@ -196,7 +196,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let ptr = self.memory.allocate(bs.len() as u64, 1)?;
self.memory.write_bytes(ptr, bs)?;
self.memory.freeze(ptr.alloc_id)?;
PrimVal::from_ptr(ptr)
PrimVal::Pointer(ptr)
}
Struct(_) => unimplemented!(),
@ -315,14 +315,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
.expect("global should have been cached (freeze)");
match global_value.data.expect("global should have been initialized") {
Value::ByRef(ptr) => self.memory.freeze(ptr.alloc_id)?,
Value::ByVal(val) => if let Some(alloc_id) = val.relocation {
Value::ByVal(val) => if let Some(alloc_id) = val.relocation() {
self.memory.freeze(alloc_id)?;
},
Value::ByValPair(a, b) => {
if let Some(alloc_id) = a.relocation {
if let Some(alloc_id) = a.relocation() {
self.memory.freeze(alloc_id)?;
}
if let Some(alloc_id) = b.relocation {
if let Some(alloc_id) = b.relocation() {
self.memory.freeze(alloc_id)?;
}
},
@ -500,7 +500,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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();
self.write_primval(dest, PrimVal::new(n), dest_ty)?;
self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
} else {
bug!("tried to assign {:?} to Layout::CEnum", kind);
}
@ -563,12 +563,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ref(_, _, ref lvalue) => {
let src = self.eval_lvalue(lvalue)?;
let (raw_ptr, extra) = self.force_allocation(src)?.to_ptr_and_extra();
let ptr = PrimVal::from_ptr(raw_ptr);
let ptr = PrimVal::Pointer(raw_ptr);
let val = match extra {
LvalueExtra::None => Value::ByVal(ptr),
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::Pointer(vtable)),
LvalueExtra::DowncastVariant(..) =>
bug!("attempted to take a reference to an enum downcast lvalue"),
};
@ -578,7 +578,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Box(ty) => {
let ptr = self.alloc_ptr(ty)?;
self.write_primval(dest, PrimVal::from_ptr(ptr), dest_ty)?;
self.write_primval(dest, PrimVal::Pointer(ptr), dest_ty)?;
}
Cast(kind, ref operand, cast_ty) => {
@ -617,7 +617,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_ptr(fn_ptr)), dest, dest_ty)?;
self.write_value(Value::ByVal(PrimVal::Pointer(fn_ptr)), dest, dest_ty)?;
},
ref other => bug!("reify fn pointer on {:?}", other),
},
@ -629,7 +629,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_ptr(fn_ptr)), dest, dest_ty)?;
self.write_value(Value::ByVal(PrimVal::Pointer(fn_ptr)), dest, dest_ty)?;
},
ref other => bug!("fn to unsafe fn cast on {:?}", other),
},
@ -1093,10 +1093,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
match ty.sty {
ty::TyBool if val.bits > 1 => Err(EvalError::InvalidBool),
ty::TyBool if val.bits() > 1 => Err(EvalError::InvalidBool),
ty::TyChar if ::std::char::from_u32(val.bits as u32).is_none()
=> Err(EvalError::InvalidChar(val.bits as u32 as u64)),
ty::TyChar if ::std::char::from_u32(val.bits() as u32).is_none()
=> Err(EvalError::InvalidChar(val.bits() as u32 as u64)),
_ => Ok(()),
}
@ -1150,23 +1150,23 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_ptr)?,
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::Pointer)?,
ty::TyBox(ty) |
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
let p = self.memory.read_ptr(ptr)?;
if self.type_is_sized(ty) {
PrimVal::from_ptr(p)
PrimVal::Pointer(p)
} else {
trace!("reading fat pointer extra of type {}", ty);
let extra = ptr.offset(self.memory.pointer_size());
let extra = match self.tcx.struct_tail(ty).sty {
ty::TyDynamic(..) => PrimVal::from_ptr(self.memory.read_ptr(extra)?),
ty::TyDynamic(..) => PrimVal::Pointer(self.memory.read_ptr(extra)?),
ty::TySlice(..) |
ty::TyStr => PrimVal::from_uint(self.memory.read_usize(extra)?),
_ => bug!("unsized primval ptr read from {:?}", ty),
};
return Ok(Some(Value::ByValPair(PrimVal::from_ptr(p), extra)));
return Ok(Some(Value::ByValPair(PrimVal::Pointer(p), extra)));
}
}
@ -1225,7 +1225,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
let ptr = src.read_ptr(&self.memory)?;
let len = PrimVal::from_uint(length as u64);
let ptr = PrimVal::from_ptr(ptr);
let ptr = PrimVal::Pointer(ptr);
self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)?;
}
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
@ -1239,8 +1239,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let trait_ref = self.tcx.erase_regions(&trait_ref);
let vtable = self.get_vtable(trait_ref)?;
let ptr = src.read_ptr(&self.memory)?;
let ptr = PrimVal::from_ptr(ptr);
let extra = PrimVal::from_ptr(vtable);
let ptr = PrimVal::Pointer(ptr);
let extra = PrimVal::Pointer(vtable);
self.write_value(Value::ByValPair(ptr, extra), dest, dest_ty)?;
},
@ -1301,12 +1301,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
Value::ByVal(val) => {
trace!("frame[{}] {:?}: {:?}", frame, local, val);
if let Some(alloc_id) = val.relocation { allocs.push(alloc_id); }
if let Some(alloc_id) = val.relocation() { allocs.push(alloc_id); }
}
Value::ByValPair(val1, val2) => {
trace!("frame[{}] {:?}: ({:?}, {:?})", frame, local, val1, val2);
if let Some(alloc_id) = val1.relocation { allocs.push(alloc_id); }
if let Some(alloc_id) = val2.relocation { allocs.push(alloc_id); }
if let Some(alloc_id) = val1.relocation() { allocs.push(alloc_id); }
if let Some(alloc_id) = val2.relocation() { allocs.push(alloc_id); }
}
}
}

View File

@ -587,18 +587,18 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
val: PrimVal,
kind: PrimValKind,
) -> EvalResult<'tcx, ()> {
if let Some(alloc_id) = val.relocation {
return self.write_ptr(dest, Pointer::new(alloc_id, val.bits));
if let Some(alloc_id) = val.relocation() {
return self.write_ptr(dest, Pointer::new(alloc_id, val.bits()));
}
use value::PrimValKind::*;
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),
I64 | U64 | F64 => (8, val.bits),
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),
I64 | U64 | F64 => (8, val.bits()),
// int -> ptr transmutes are handled here
FnPtr | Ptr => return self.write_usize(dest, val.bits),
FnPtr | Ptr => return self.write_usize(dest, val.bits()),
};
self.write_uint(dest, bits, size)

View File

@ -66,7 +66,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
macro_rules! overflow {
($op:ident, $l:expr, $r:expr) => ({
let (val, overflowed) = $l.$op($r);
let primval = PrimVal::new(val as u64);
let primval = PrimVal::Bytes(val as u64);
Ok((primval, overflowed))
})
}
@ -112,7 +112,7 @@ macro_rules! float_arithmetic {
let l = $from_bits($l);
let r = $from_bits($r);
let bits = $to_bits(l $float_op r);
PrimVal::new(bits)
PrimVal::Bytes(bits)
})
}
@ -148,7 +148,7 @@ pub fn binary_op<'tcx>(
return Ok((unrelated_ptr_ops(bin_op, left_ptr, right_ptr)?, false));
}
let (l, r) = (left.bits, right.bits);
let (l, r) = (left.bits(), right.bits());
// These ops can have an RHS with a different numeric type.
if bin_op == Shl || bin_op == Shr {
@ -165,7 +165,7 @@ pub fn binary_op<'tcx>(
// Cast to `u32` because `overflowing_sh{l,r}` only take `u32`, then apply the bitmask
// to ensure it's within the valid shift value range.
let r = (right.bits as u32) & (type_bits - 1);
let r = (right.bits() as u32) & (type_bits - 1);
return match bin_op {
Shl => int_shift!(left_kind, overflowing_shl, l, r),
@ -213,9 +213,9 @@ pub fn binary_op<'tcx>(
(Gt, _) => PrimVal::from_bool(l > r),
(Ge, _) => PrimVal::from_bool(l >= r),
(BitOr, _) => PrimVal::new(l | r),
(BitAnd, _) => PrimVal::new(l & r),
(BitXor, _) => PrimVal::new(l ^ r),
(BitOr, _) => PrimVal::Bytes(l | r),
(BitAnd, _) => PrimVal::Bytes(l & r),
(BitXor, _) => PrimVal::Bytes(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),
@ -254,25 +254,25 @@ pub fn unary_op<'tcx>(
use value::PrimValKind::*;
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, U16) => !(val.bits as u16) as u64,
(Not, U32) => !(val.bits as u32) as u64,
(Not, U64) => !val.bits,
(Not, U8) => !(val.bits() as u8) as u64,
(Not, U16) => !(val.bits() as u16) as u64,
(Not, U32) => !(val.bits() as u32) as u64,
(Not, U64) => !val.bits(),
(Not, I8) => !(val.bits as i8) as u64,
(Not, I16) => !(val.bits as i16) as u64,
(Not, I32) => !(val.bits as i32) as u64,
(Not, I64) => !(val.bits as i64) as u64,
(Not, I8) => !(val.bits() as i8) as u64,
(Not, I16) => !(val.bits() as i16) as u64,
(Not, I32) => !(val.bits() as i32) as u64,
(Not, I64) => !(val.bits() as i64) as u64,
(Neg, I8) => -(val.bits as i8) as u64,
(Neg, I16) => -(val.bits as i16) as u64,
(Neg, I32) => -(val.bits as i32) as u64,
(Neg, I64) => -(val.bits as i64) as u64,
(Neg, I8) => -(val.bits() as i8) as u64,
(Neg, I16) => -(val.bits() as i16) as u64,
(Neg, I32) => -(val.bits() as i32) as u64,
(Neg, I64) => -(val.bits() as i64) as u64,
(Neg, F32) => f32_to_bits(-bits_to_f32(val.bits)),
(Neg, F64) => f64_to_bits(-bits_to_f64(val.bits)),
(Neg, F32) => f32_to_bits(-bits_to_f32(val.bits())),
(Neg, F64) => f64_to_bits(-bits_to_f64(val.bits())),
_ => {
let msg = format!("unimplemented unary op: {:?}, {:?}", un_op, val);
@ -280,5 +280,5 @@ pub fn unary_op<'tcx>(
}
};
Ok(PrimVal::new(bits))
Ok(PrimVal::Bytes(bits))
}

View File

@ -47,7 +47,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let ptr = arg_vals[0].read_ptr(&self.memory)?;
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), dest_ty)?;
self.write_primval(dest, PrimVal::Pointer(new_ptr), dest_ty)?;
}
"assume" => {
@ -171,7 +171,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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), dest_ty)?;
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
}
"drop_in_place" => {
@ -235,16 +235,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Value::ByRef(ptr)
},
None => match this.ty_to_primval_kind(dest_ty) {
Ok(_) => Value::ByVal(PrimVal::new(0)),
Ok(_) => Value::ByVal(PrimVal::Bytes(0)),
Err(_) => {
let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?;
this.memory.write_repeat(ptr, 0, size)?;
Value::ByRef(ptr)
}
},
Some(Value::ByVal(_)) => Value::ByVal(PrimVal::new(0)),
Some(Value::ByVal(_)) => Value::ByVal(PrimVal::Bytes(0)),
Some(Value::ByValPair(..)) =>
Value::ByValPair(PrimVal::new(0), PrimVal::new(0)),
Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)),
};
Ok(Some(zero_val))
};
@ -292,7 +292,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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), dest_ty)?;
self.write_primval(dest, PrimVal::Pointer(result_ptr), dest_ty)?;
}
"overflowing_sub" => {
@ -361,7 +361,7 @@ 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), dest_ty)?;
self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
}
"transmute" => {
@ -507,18 +507,18 @@ macro_rules! integer_intrinsic {
use value::PrimValKind::*;
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,
U16 => (val.bits as u16).$method() as u64,
I32 => (val.bits as i32).$method() as u64,
U32 => (val.bits as u32).$method() as u64,
I64 => (val.bits as i64).$method() as u64,
U64 => (val.bits as u64).$method() as u64,
I8 => (val.bits() as i8).$method() as u64,
U8 => (val.bits() as u8).$method() as u64,
I16 => (val.bits() as i16).$method() as u64,
U16 => (val.bits() as u16).$method() as u64,
I32 => (val.bits() as i32).$method() as u64,
U32 => (val.bits() as u32).$method() as u64,
I64 => (val.bits() as i64).$method() as u64,
U64 => (val.bits() as u64).$method() as u64,
_ => bug!("invalid `{}` argument: {:?}", $name, val),
};
PrimVal::new(bits)
PrimVal::Bytes(bits)
});
}

View File

@ -336,7 +336,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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), dest_ty)?;
self.write_primval(dest, PrimVal::Pointer(ptr), dest_ty)?;
}
"__rust_deallocate" => {
@ -352,7 +352,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
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), dest_ty)?;
self.write_primval(dest, PrimVal::Pointer(new_ptr), dest_ty)?;
}
"memcmp" => {
@ -372,7 +372,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
};
self.write_primval(dest, PrimVal::new(result as u64), dest_ty)?;
self.write_primval(dest, PrimVal::Bytes(result as u64), dest_ty)?;
}
"memchr" => {
@ -527,7 +527,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ptr
},
};
args[0].0 = Value::ByVal(PrimVal::from_ptr(ptr));
args[0].0 = Value::ByVal(PrimVal::Pointer(ptr));
args[0].1 = self.tcx.mk_mut_ptr(args[0].1);
}
@ -550,7 +550,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let idx = self.tcx.get_vtable_index_of_object_method(data, def_id) as u64;
if let Some(&mut(ref mut first_arg, ref mut first_ty)) = args.get_mut(0) {
let (self_ptr, vtable) = first_arg.expect_ptr_vtable_pair(&self.memory)?;
*first_arg = Value::ByVal(PrimVal::from_ptr(self_ptr));
*first_arg = Value::ByVal(PrimVal::Pointer(self_ptr));
let idx = idx + 3;
let offset = idx * self.memory.pointer_size();
let fn_ptr = self.memory.read_ptr(vtable.offset(offset))?;
@ -633,7 +633,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
};
// run drop impl before the fields' drop impls
if let Some(drop_def_id) = adt_def.destructor() {
drop.push((drop_def_id, Value::ByVal(PrimVal::from_ptr(adt_ptr)), substs));
drop.push((drop_def_id, Value::ByVal(PrimVal::Pointer(adt_ptr)), substs));
}
let layout = self.type_layout(ty)?;
let fields = match *layout {
@ -701,7 +701,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let (def_id, substs, _abi, sig) = self.memory.get_fn(drop_fn.alloc_id)?;
let real_ty = sig.inputs()[0];
self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
drop.push((def_id, Value::ByVal(PrimVal::from_ptr(ptr)), substs));
drop.push((def_id, Value::ByVal(PrimVal::Pointer(ptr)), substs));
} else {
// just a sanity check
assert_eq!(drop_fn.offset, 0);

View File

@ -46,13 +46,17 @@ pub enum Value {
/// A `PrimVal` represents an immediate, primitive value existing outside of an allocation. It is
/// considered to be like a
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PrimVal {
pub bits: u64,
pub enum PrimVal {
Bytes(u64),
// FIXME(solson): Rename this variant to Ptr.
// FIXME(solson): Outdated comment, pulled from `relocations` field I deleted.
/// This field is initialized when the `PrimVal` represents a pointer into an `Allocation`. An
/// `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<AllocId>,
Pointer(Pointer),
Undefined,
}
#[derive(Clone, Copy, Debug, PartialEq)]
@ -110,56 +114,64 @@ impl<'a, 'tcx: 'a> Value {
}
impl PrimVal {
pub fn new(bits: u64) -> Self {
PrimVal { bits: bits, relocation: None }
// FIXME(solson): Remove this. It's a temporary function to aid refactoring, but it shouldn't
// stick around with this name.
pub fn bits(&self) -> u64 {
match *self {
PrimVal::Bytes(b) => b,
PrimVal::Pointer(p) => p.offset,
PrimVal::Undefined => panic!(".bits()() on PrimVal::Undefined"),
}
}
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, ptr.alloc_id)
// FIXME(solson): Remove this. It's a temporary function to aid refactoring, but it shouldn't
// stick around with this name.
pub fn relocation(&self) -> Option<AllocId> {
if let PrimVal::Pointer(ref p) = *self {
Some(p.alloc_id)
} else {
None
}
}
pub fn from_bool(b: bool) -> Self {
PrimVal::new(b as u64)
PrimVal::Bytes(b as u64)
}
pub fn from_char(c: char) -> Self {
PrimVal::new(c as u64)
PrimVal::Bytes(c as u64)
}
pub fn from_f32(f: f32) -> Self {
PrimVal::new(f32_to_bits(f))
PrimVal::Bytes(f32_to_bits(f))
}
pub fn from_f64(f: f64) -> Self {
PrimVal::new(f64_to_bits(f))
PrimVal::Bytes(f64_to_bits(f))
}
pub fn from_uint(n: u64) -> Self {
PrimVal::new(n)
PrimVal::Bytes(n)
}
pub fn from_int(n: i64) -> Self {
PrimVal::new(n as u64)
PrimVal::Bytes(n as u64)
}
pub fn to_f32(self) -> f32 {
assert!(self.relocation.is_none());
bits_to_f32(self.bits)
assert!(self.relocation().is_none());
bits_to_f32(self.bits())
}
pub fn to_f64(self) -> f64 {
assert!(self.relocation.is_none());
bits_to_f64(self.bits)
assert!(self.relocation().is_none());
bits_to_f64(self.bits())
}
pub fn to_ptr(self) -> Pointer {
self.relocation.map(|alloc_id| {
Pointer::new(alloc_id, self.bits)
}).unwrap_or_else(|| Pointer::from_int(self.bits))
self.relocation().map(|alloc_id| {
Pointer::new(alloc_id, self.bits())
}).unwrap_or_else(|| Pointer::from_int(self.bits()))
}
pub fn try_as_uint<'tcx>(self) -> EvalResult<'tcx, u64> {
@ -170,24 +182,24 @@ impl PrimVal {
if let Some(ptr) = self.try_as_ptr() {
return ptr.to_int().expect("non abstract ptr") as u64;
}
self.bits
self.bits()
}
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
self.bits() as i64
}
pub fn try_as_ptr(self) -> Option<Pointer> {
self.relocation.map(|alloc_id| {
Pointer::new(alloc_id, self.bits)
self.relocation().map(|alloc_id| {
Pointer::new(alloc_id, self.bits())
})
}
pub fn try_as_bool<'tcx>(self) -> EvalResult<'tcx, bool> {
match self.bits {
match self.bits() {
0 => Ok(false),
1 => Ok(true),
_ => Err(EvalError::InvalidBool),