]> git.lizzy.rs Git - rust.git/blob - src/helpers.rs
Fix some clippy lints
[rust.git] / src / helpers.rs
1 use mir;
2 use rustc::ty::Ty;
3 use rustc::ty::layout::{LayoutOf, Size};
4
5 use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy};
6 use rustc_mir::interpret::sign_extend;
7
8 pub trait EvalContextExt<'tcx> {
9     fn wrapping_pointer_offset(
10         &self,
11         ptr: Scalar,
12         pointee_ty: Ty<'tcx>,
13         offset: i64,
14     ) -> EvalResult<'tcx, Scalar>;
15
16     fn pointer_offset(
17         &self,
18         ptr: Scalar,
19         pointee_ty: Ty<'tcx>,
20         offset: i64,
21     ) -> EvalResult<'tcx, Scalar>;
22
23     fn value_to_isize(
24         &self,
25         value: ValTy<'tcx>,
26     ) -> EvalResult<'tcx, i64>;
27
28     fn value_to_usize(
29         &self,
30         value: ValTy<'tcx>,
31     ) -> EvalResult<'tcx, u64>;
32
33     fn value_to_i32(
34         &self,
35         value: ValTy<'tcx>,
36     ) -> EvalResult<'tcx, i32>;
37
38     fn value_to_u8(
39         &self,
40         value: ValTy<'tcx>,
41     ) -> EvalResult<'tcx, u8>;
42 }
43
44 impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
45     fn wrapping_pointer_offset(
46         &self,
47         ptr: Scalar,
48         pointee_ty: Ty<'tcx>,
49         offset: i64,
50     ) -> EvalResult<'tcx, Scalar> {
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.ptr_wrapping_signed_offset(offset, self)
55     }
56
57     fn pointer_offset(
58         &self,
59         ptr: Scalar,
60         pointee_ty: Ty<'tcx>,
61         offset: i64,
62     ) -> EvalResult<'tcx, Scalar> {
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
66         // allocation.
67
68         if ptr.is_null()? {
69             // NULL pointers must only be offset by 0
70             return if offset == 0 {
71                 Ok(ptr)
72             } else {
73                 err!(InvalidNullPointerUsage)
74             };
75         }
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          if let Some(offset) = offset.checked_mul(pointee_size) {
79             let ptr = 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 Scalar::Ptr(ptr) = ptr {
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);
86             }
87             Ok(ptr)
88         } else {
89             err!(Overflow(mir::BinOp::Mul))
90         }
91     }
92
93     fn value_to_isize(
94         &self,
95         value: ValTy<'tcx>,
96     ) -> EvalResult<'tcx, i64> {
97         assert_eq!(value.ty, self.tcx.types.isize);
98         let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?;
99         let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?;
100         Ok(raw as i64)
101     }
102
103     fn value_to_usize(
104         &self,
105         value: ValTy<'tcx>,
106     ) -> EvalResult<'tcx, u64> {
107         assert_eq!(value.ty, self.tcx.types.usize);
108         self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64)
109     }
110
111     fn value_to_i32(
112         &self,
113         value: ValTy<'tcx>,
114     ) -> EvalResult<'tcx, i32> {
115         assert_eq!(value.ty, self.tcx.types.i32);
116         let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?;
117         let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?;
118         Ok(raw as i32)
119     }
120
121     fn value_to_u8(
122         &self,
123         value: ValTy<'tcx>,
124     ) -> EvalResult<'tcx, u8> {
125         assert_eq!(value.ty, self.tcx.types.u8);
126         self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8)
127     }
128 }