]> git.lizzy.rs Git - rust.git/blob - src/operator.rs
fix newer getrandom on Windows
[rust.git] / src / operator.rs
1 use log::trace;
2
3 use rustc_middle::{mir, ty::Ty};
4
5 use crate::*;
6
7 pub trait EvalContextExt<'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
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> {
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                 // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
49                 let left = self.force_bits(left.to_scalar()?, left.layout.size)?;
50                 let right = self.force_bits(right.to_scalar()?, right.layout.size)?;
51                 let res = match bin_op {
52                     Lt => left < right,
53                     Le => left <= right,
54                     Gt => left > right,
55                     Ge => left >= right,
56                     _ => bug!("We already established it has to be one of these operators."),
57                 };
58                 (Scalar::from_bool(res), false, self.tcx.types.bool)
59             }
60
61             Offset => {
62                 let pointee_ty =
63                     left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty;
64                 let ptr = self.ptr_offset_inbounds(
65                     left.to_scalar()?,
66                     pointee_ty,
67                     right.to_scalar()?.to_machine_isize(self)?,
68                 )?;
69                 (ptr, false, left.layout.ty)
70             }
71
72             _ => bug!("Invalid operator on pointers: {:?}", bin_op),
73         })
74     }
75
76     fn ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool> {
77         let size = self.pointer_size();
78         // Just compare the integers.
79         // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
80         let left = self.force_bits(left, size)?;
81         let right = self.force_bits(right, size)?;
82         Ok(left == right)
83     }
84 }