X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Foperator.rs;h=cf92aed9ccb2c5edcf98e451e042f56b142198e3;hb=20e31dbdad67080eb83aa3b5330dfe2f116f9900;hp=f047f4f4fad01d64ff5fcff5766b16dd911f7ab1;hpb=9d3fdeeed713a36be3b858c423ee17f9c053303d;p=rust.git diff --git a/src/operator.rs b/src/operator.rs index f047f4f4fad..cf92aed9ccb 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,65 +1,46 @@ -use rustc::ty::{Ty, layout::LayoutOf}; -use rustc::mir; +use log::trace; + +use rustc_middle::{mir, ty::Ty}; use crate::*; pub trait EvalContextExt<'tcx> { - fn pointer_inbounds( - &self, - ptr: Pointer - ) -> InterpResult<'tcx>; - fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)>; + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool>; - - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar>; + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { - /// Test if the pointer is in-bounds of a live allocation. - #[inline] - fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { - let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) - } - fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { - use rustc::mir::BinOp::*; + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); Ok(match bin_op { Eq | Ne => { // This supports fat pointers. - let eq = match (*left, *right) { - (Immediate::Scalar(left), Immediate::Scalar(right)) => - self.ptr_eq(left.not_undef()?, right.not_undef()?)?, - (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => - self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? && - self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, + #[rustfmt::skip] + let eq = match (**left, **right) { + (Immediate::Scalar(left), Immediate::Scalar(right)) => { + self.ptr_eq(left.check_init()?, right.check_init()?)? + } + (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { + self.ptr_eq(left1.check_init()?, right1.check_init()?)? + && self.ptr_eq(left2.check_init()?, right2.check_init()?)? + } _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; - (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false) + (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) } Lt | Le | Gt | Ge => { @@ -74,31 +55,25 @@ fn binary_ptr_op( Ge => left >= right, _ => bug!("We already established it has to be one of these operators."), }; - (Scalar::from_bool(res), false) + (Scalar::from_bool(res), false, self.tcx.types.bool) } Offset => { - let pointee_ty = left.layout.ty - .builtin_deref(true) - .expect("Offset called on non-ptr type") - .ty; - let ptr = self.pointer_offset_inbounds( + let pointee_ty = + left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; + let ptr = self.ptr_offset_inbounds( left.to_scalar()?, pointee_ty, - right.to_scalar()?.to_isize(self)?, + right.to_scalar()?.to_machine_isize(self)?, )?; - (ptr, false) + (ptr, false, left.layout.ty) } - _ => bug!("Invalid operator on pointers: {:?}", bin_op) + _ => bug!("Invalid operator on pointers: {:?}", bin_op), }) } - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool> { + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); // Just compare the integers. // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? @@ -106,41 +81,4 @@ fn ptr_eq( let right = self.force_bits(right, size)?; Ok(left == right) } - - /// Raises an error if the offset moves the pointer outside of its allocation. - /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing - /// moves in there because the size is 0). We also consider the NULL pointer its own separate - /// allocation, and all the remaining integers pointers their own allocation. - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar> { - // FIXME: assuming here that type size is less than `i64::max_value()`. - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - let offset = offset - .checked_mul(pointee_size) - .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; - // Now let's see what kind of pointer this is. - let ptr = if offset == 0 { - match ptr { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => { - // Offset 0 on an integer. We accept that, pretending there is - // a little zero-sized allocation here. - return Ok(ptr); - } - } - } else { - // Offset > 0. We *require* a pointer. - self.force_ptr(ptr)? - }; - // Both old and new pointer must be in-bounds of a *live* allocation. - // (Of the same allocation, but that part is trivial with our representation.) - self.pointer_inbounds(ptr)?; - let ptr = ptr.signed_offset(offset, self)?; - self.pointer_inbounds(ptr)?; - Ok(Scalar::Ptr(ptr)) - } }