1 use log::trace; 2 3 use rustc_middle::{mir, ty::Ty}; 4 5 use crate::*; 6 7 pub trait EvalContextExt<'tcx> { binary_ptr_op( &self, bin_op: mir::BinOp, left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)>8 fn binary_ptr_op( 9 &self, 10 bin_op: mir::BinOp, 11 left: &ImmTy<'tcx, Tag>, 12 right: &ImmTy<'tcx, Tag>, 13 ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)>; 14 ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool>15 fn ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool>; 16 } 17 18 impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { binary_ptr_op( &self, bin_op: mir::BinOp, left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)>19 fn binary_ptr_op( 20 &self, 21 bin_op: mir::BinOp, 22 left: &ImmTy<'tcx, Tag>, 23 right: &ImmTy<'tcx, Tag>, 24 ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)> { 25 use rustc_middle::mir::BinOp::*; 26 27 trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); 28 29 Ok(match bin_op { 30 Eq | Ne => { 31 // This supports fat pointers. 32 #[rustfmt::skip] 33 let eq = match (**left, **right) { 34 (Immediate::Scalar(left), Immediate::Scalar(right)) => { 35 self.ptr_eq(left.check_init()?, right.check_init()?)? 36 } 37 (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { 38 self.ptr_eq(left1.check_init()?, right1.check_init()?)? 39 && self.ptr_eq(left2.check_init()?, right2.check_init()?)? 40 } 41 _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), 42 }; 43 (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) 44 } 45 46 Lt | Le | Gt | Ge => { 47 // Just compare the integers. 48 let left = left.to_scalar()?.to_bits(left.layout.size)?; 49 let right = right.to_scalar()?.to_bits(right.layout.size)?; 50 let res = match bin_op { 51 Lt => left < right, 52 Le => left <= right, 53 Gt => left > right, 54 Ge => left >= right, 55 _ => bug!("We already established it has to be one of these operators."), 56 }; 57 (Scalar::from_bool(res), false, self.tcx.types.bool) 58 } 59 60 Offset => { 61 let pointee_ty = 62 left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; 63 let ptr = self.ptr_offset_inbounds( 64 self.scalar_to_ptr(left.to_scalar()?), 65 pointee_ty, 66 right.to_scalar()?.to_machine_isize(self)?, 67 )?; 68 (Scalar::from_maybe_pointer(ptr, self), false, left.layout.ty) 69 } 70 71 _ => bug!("Invalid operator on pointers: {:?}", bin_op), 72 }) 73 } 74 ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool>75 fn ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool> { 76 let size = self.pointer_size(); 77 // Just compare the integers. 78 let left = left.to_bits(size)?; 79 let right = right.to_bits(size)?; 80 Ok(left == right) 81 } 82 } 83