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