3 use rustc::ty::layout::LayoutOf;
5 use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy};
6 use rustc_mir::interpret::sign_extend;
8 pub trait EvalContextExt<'tcx> {
9 fn wrapping_pointer_offset(
14 ) -> EvalResult<'tcx, Pointer>;
21 ) -> EvalResult<'tcx, Pointer>;
26 ) -> EvalResult<'tcx, i64>;
31 ) -> EvalResult<'tcx, u64>;
36 ) -> EvalResult<'tcx, i32>;
41 ) -> EvalResult<'tcx, u8>;
44 impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
45 fn wrapping_pointer_offset(
50 ) -> EvalResult<'tcx, Pointer> {
51 // FIXME: assuming here that type size is < i64::max_value()
52 let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
53 let offset = offset.overflowing_mul(pointee_size).0;
54 ptr.wrapping_signed_offset(offset, self)
62 ) -> EvalResult<'tcx, Pointer> {
63 // This function raises an error if the offset moves the pointer outside of its allocation. We consider
64 // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
65 // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
69 // NULL pointers must only be offset by 0
70 return if offset == 0 {
73 err!(InvalidNullPointerUsage)
76 // FIXME: assuming here that type size is < i64::max_value()
77 let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
78 return if let Some(offset) = offset.checked_mul(pointee_size) {
79 let ptr = ptr.signed_offset(offset, self)?;
80 // Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
81 if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
82 self.memory.check_bounds(ptr, false)?;
83 } else if ptr.is_null()? {
84 // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
85 return err!(InvalidNullPointerUsage);
89 err!(Overflow(mir::BinOp::Mul))
96 ) -> EvalResult<'tcx, i64> {
97 assert_eq!(value.ty, self.tcx.types.isize);
98 let raw = self.value_to_primval(value)?.to_bytes()?;
99 let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?;
106 ) -> EvalResult<'tcx, u64> {
107 assert_eq!(value.ty, self.tcx.types.usize);
108 self.value_to_primval(value)?.to_bytes().map(|v| v as u64)
114 ) -> EvalResult<'tcx, i32> {
115 assert_eq!(value.ty, self.tcx.types.i32);
116 let raw = self.value_to_primval(value)?.to_bytes()?;
117 let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?;
124 ) -> EvalResult<'tcx, u8> {
125 assert_eq!(value.ty, self.tcx.types.u8);
126 self.value_to_primval(value)?.to_bytes().map(|v| v as u8)