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:
parent
9674e507ca
commit
b36a83171b
26
src/cast.rs
26
src/cast.rs
@ -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))),
|
||||
}
|
||||
}
|
||||
|
@ -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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
70
src/value.rs
70
src/value.rs
@ -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),
|
||||
|
Loading…
x
Reference in New Issue
Block a user