]>
Commit | Line | Data |
---|---|---|
6a06907d | 1 | use std::convert::{TryFrom, TryInto}; |
ba9703b0 XL |
2 | use std::fmt; |
3 | ||
dfeec247 XL |
4 | use rustc_apfloat::{ |
5 | ieee::{Double, Single}, | |
6 | Float, | |
7 | }; | |
532ac7d7 | 8 | use rustc_macros::HashStable; |
ba9703b0 | 9 | use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; |
ea8adc8c | 10 | |
6a06907d | 11 | use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; |
ea8adc8c | 12 | |
29967ef6 | 13 | use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; |
94b46f34 | 14 | |
1b1a35ee | 15 | /// Represents the result of const evaluation via the `eval_to_allocation` query. |
6a06907d | 16 | #[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)] |
1b1a35ee | 17 | pub struct ConstAlloc<'tcx> { |
0731742a | 18 | // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` |
a1dfa0c6 XL |
19 | // (so you can use `AllocMap::unwrap_memory`). |
20 | pub alloc_id: AllocId, | |
21 | pub ty: Ty<'tcx>, | |
22 | } | |
23 | ||
e1599b0c XL |
24 | /// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for |
25 | /// array length computations, enum discriminants and the pattern matching logic. | |
3dfed10e | 26 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] |
ba9703b0 | 27 | #[derive(HashStable)] |
94b46f34 | 28 | pub enum ConstValue<'tcx> { |
9fa01778 | 29 | /// Used only for types with `layout::abi::Scalar` ABI and ZSTs. |
b7449926 | 30 | /// |
f9f354fc | 31 | /// Not using the enum `Value` to encode that this must not be `Uninit`. |
94b46f34 | 32 | Scalar(Scalar), |
0bf4aa26 | 33 | |
dc9dc135 | 34 | /// Used only for `&[u8]` and `&str` |
dfeec247 | 35 | Slice { data: &'tcx Allocation, start: usize, end: usize }, |
9fa01778 | 36 | |
dc9dc135 XL |
37 | /// A value not represented/representable by `Scalar` or `Slice` |
38 | ByRef { | |
dc9dc135 XL |
39 | /// The backing memory of the value, may contain more memory than needed for just the value |
40 | /// in order to share `Allocation`s between values | |
41 | alloc: &'tcx Allocation, | |
416331ca XL |
42 | /// Offset into `alloc` |
43 | offset: Size, | |
dc9dc135 | 44 | }, |
94b46f34 XL |
45 | } |
46 | ||
6a06907d | 47 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
dc9dc135 | 48 | static_assert_size!(ConstValue<'_>, 32); |
9fa01778 | 49 | |
6a06907d XL |
50 | impl From<Scalar> for ConstValue<'tcx> { |
51 | fn from(s: Scalar) -> Self { | |
52 | Self::Scalar(s) | |
53 | } | |
54 | } | |
55 | ||
56 | impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { | |
57 | type Lifted = ConstValue<'tcx>; | |
58 | fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> { | |
59 | Some(match self { | |
60 | ConstValue::Scalar(s) => ConstValue::Scalar(s), | |
61 | ConstValue::Slice { data, start, end } => { | |
62 | ConstValue::Slice { data: tcx.lift(data)?, start, end } | |
63 | } | |
64 | ConstValue::ByRef { alloc, offset } => { | |
65 | ConstValue::ByRef { alloc: tcx.lift(alloc)?, offset } | |
66 | } | |
67 | }) | |
68 | } | |
69 | } | |
70 | ||
94b46f34 XL |
71 | impl<'tcx> ConstValue<'tcx> { |
72 | #[inline] | |
b7449926 | 73 | pub fn try_to_scalar(&self) -> Option<Scalar> { |
94b46f34 | 74 | match *self { |
dfeec247 | 75 | ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None, |
94b46f34 XL |
76 | ConstValue::Scalar(val) => Some(val), |
77 | } | |
78 | } | |
74b04a01 | 79 | |
6a06907d XL |
80 | pub fn try_to_scalar_int(&self) -> Option<ScalarInt> { |
81 | Some(self.try_to_scalar()?.assert_int()) | |
82 | } | |
83 | ||
74b04a01 | 84 | pub fn try_to_bits(&self, size: Size) -> Option<u128> { |
6a06907d | 85 | self.try_to_scalar_int()?.to_bits(size).ok() |
74b04a01 XL |
86 | } |
87 | ||
3dfed10e | 88 | pub fn try_to_bool(&self) -> Option<bool> { |
6a06907d | 89 | self.try_to_scalar_int()?.try_into().ok() |
3dfed10e XL |
90 | } |
91 | ||
92 | pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> { | |
6a06907d | 93 | self.try_to_scalar_int()?.try_to_machine_usize(tcx).ok() |
3dfed10e XL |
94 | } |
95 | ||
74b04a01 XL |
96 | pub fn try_to_bits_for_ty( |
97 | &self, | |
98 | tcx: TyCtxt<'tcx>, | |
99 | param_env: ParamEnv<'tcx>, | |
100 | ty: Ty<'tcx>, | |
101 | ) -> Option<u128> { | |
3dfed10e | 102 | let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; |
74b04a01 XL |
103 | self.try_to_bits(size) |
104 | } | |
105 | ||
106 | pub fn from_bool(b: bool) -> Self { | |
107 | ConstValue::Scalar(Scalar::from_bool(b)) | |
108 | } | |
109 | ||
110 | pub fn from_u64(i: u64) -> Self { | |
111 | ConstValue::Scalar(Scalar::from_u64(i)) | |
112 | } | |
113 | ||
114 | pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { | |
115 | ConstValue::Scalar(Scalar::from_machine_usize(i, cx)) | |
116 | } | |
0531ce1d XL |
117 | } |
118 | ||
0bf4aa26 | 119 | /// A `Scalar` represents an immediate, primitive value existing outside of a |
5869c6ff | 120 | /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 16 bytes in |
0bf4aa26 XL |
121 | /// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes |
122 | /// of a simple value or a pointer into another `Allocation` | |
3dfed10e | 123 | #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] |
ba9703b0 | 124 | #[derive(HashStable)] |
f9f354fc | 125 | pub enum Scalar<Tag = ()> { |
0bf4aa26 | 126 | /// The raw bytes of a simple value. |
29967ef6 | 127 | Int(ScalarInt), |
0bf4aa26 XL |
128 | |
129 | /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of | |
130 | /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the | |
131 | /// relocation and its associated offset together as a `Pointer` here. | |
f9f354fc | 132 | Ptr(Pointer<Tag>), |
0bf4aa26 XL |
133 | } |
134 | ||
6a06907d | 135 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
48663c56 | 136 | static_assert_size!(Scalar, 24); |
9fa01778 | 137 | |
f9f354fc XL |
138 | // We want the `Debug` output to be readable as it is used by `derive(Debug)` for |
139 | // all the Miri types. | |
140 | impl<Tag: fmt::Debug> fmt::Debug for Scalar<Tag> { | |
dc9dc135 XL |
141 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
142 | match self { | |
dfeec247 | 143 | Scalar::Ptr(ptr) => write!(f, "{:?}", ptr), |
29967ef6 | 144 | Scalar::Int(int) => write!(f, "{:?}", int), |
dc9dc135 XL |
145 | } |
146 | } | |
147 | } | |
148 | ||
f9f354fc | 149 | impl<Tag: fmt::Debug> fmt::Display for Scalar<Tag> { |
a1dfa0c6 XL |
150 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
151 | match self { | |
f9f354fc | 152 | Scalar::Ptr(ptr) => write!(f, "pointer to {}", ptr), |
29967ef6 | 153 | Scalar::Int { .. } => fmt::Debug::fmt(self, f), |
a1dfa0c6 XL |
154 | } |
155 | } | |
156 | } | |
157 | ||
dc9dc135 XL |
158 | impl<Tag> From<Single> for Scalar<Tag> { |
159 | #[inline(always)] | |
160 | fn from(f: Single) -> Self { | |
161 | Scalar::from_f32(f) | |
162 | } | |
163 | } | |
164 | ||
165 | impl<Tag> From<Double> for Scalar<Tag> { | |
166 | #[inline(always)] | |
167 | fn from(f: Double) -> Self { | |
168 | Scalar::from_f64(f) | |
169 | } | |
170 | } | |
171 | ||
172 | impl Scalar<()> { | |
dc9dc135 XL |
173 | /// Tag this scalar with `new_tag` if it is a pointer, leave it unchanged otherwise. |
174 | /// | |
175 | /// Used by `MemPlace::replace_tag`. | |
0bf4aa26 | 176 | #[inline] |
48663c56 | 177 | pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> { |
0bf4aa26 | 178 | match self { |
48663c56 | 179 | Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)), |
29967ef6 | 180 | Scalar::Int(int) => Scalar::Int(int), |
0bf4aa26 XL |
181 | } |
182 | } | |
183 | } | |
184 | ||
185 | impl<'tcx, Tag> Scalar<Tag> { | |
29967ef6 XL |
186 | pub const ZST: Self = Scalar::Int(ScalarInt::ZST); |
187 | ||
dc9dc135 XL |
188 | /// Erase the tag from the scalar, if any. |
189 | /// | |
190 | /// Used by error reporting code to avoid having the error type depend on `Tag`. | |
0bf4aa26 XL |
191 | #[inline] |
192 | pub fn erase_tag(self) -> Scalar { | |
193 | match self { | |
194 | Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()), | |
29967ef6 | 195 | Scalar::Int(int) => Scalar::Int(int), |
0bf4aa26 XL |
196 | } |
197 | } | |
198 | ||
b7449926 | 199 | #[inline] |
ba9703b0 | 200 | pub fn null_ptr(cx: &impl HasDataLayout) -> Self { |
29967ef6 | 201 | Scalar::Int(ScalarInt::null(cx.data_layout().pointer_size)) |
b7449926 XL |
202 | } |
203 | ||
ba9703b0 XL |
204 | #[inline(always)] |
205 | fn ptr_op( | |
206 | self, | |
207 | dl: &TargetDataLayout, | |
208 | f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>, | |
209 | f_ptr: impl FnOnce(Pointer<Tag>) -> InterpResult<'tcx, Pointer<Tag>>, | |
210 | ) -> InterpResult<'tcx, Self> { | |
94b46f34 | 211 | match self { |
29967ef6 | 212 | Scalar::Int(int) => Ok(Scalar::Int(int.ptr_sized_op(dl, f_int)?)), |
ba9703b0 | 213 | Scalar::Ptr(ptr) => Ok(Scalar::Ptr(f_ptr(ptr)?)), |
a1dfa0c6 XL |
214 | } |
215 | } | |
216 | ||
ba9703b0 XL |
217 | #[inline] |
218 | pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { | |
219 | let dl = cx.data_layout(); | |
220 | self.ptr_op(dl, |int| dl.offset(int, i.bytes()), |ptr| ptr.offset(i, dl)) | |
221 | } | |
222 | ||
a1dfa0c6 XL |
223 | #[inline] |
224 | pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self { | |
225 | let dl = cx.data_layout(); | |
ba9703b0 XL |
226 | self.ptr_op( |
227 | dl, | |
228 | |int| Ok(dl.overflowing_offset(int, i.bytes()).0), | |
229 | |ptr| Ok(ptr.wrapping_offset(i, dl)), | |
230 | ) | |
231 | .unwrap() | |
ea8adc8c XL |
232 | } |
233 | ||
b7449926 | 234 | #[inline] |
dc9dc135 | 235 | pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { |
a1dfa0c6 | 236 | let dl = cx.data_layout(); |
ba9703b0 | 237 | self.ptr_op(dl, |int| dl.signed_offset(int, i), |ptr| ptr.signed_offset(i, dl)) |
ea8adc8c XL |
238 | } |
239 | ||
b7449926 | 240 | #[inline] |
a1dfa0c6 XL |
241 | pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { |
242 | let dl = cx.data_layout(); | |
ba9703b0 XL |
243 | self.ptr_op( |
244 | dl, | |
245 | |int| Ok(dl.overflowing_signed_offset(int, i).0), | |
246 | |ptr| Ok(ptr.wrapping_signed_offset(i, dl)), | |
247 | ) | |
248 | .unwrap() | |
ea8adc8c XL |
249 | } |
250 | ||
b7449926 XL |
251 | #[inline] |
252 | pub fn from_bool(b: bool) -> Self { | |
29967ef6 | 253 | Scalar::Int(b.into()) |
ea8adc8c XL |
254 | } |
255 | ||
b7449926 XL |
256 | #[inline] |
257 | pub fn from_char(c: char) -> Self { | |
29967ef6 | 258 | Scalar::Int(c.into()) |
ea8adc8c | 259 | } |
ea8adc8c | 260 | |
dfeec247 XL |
261 | #[inline] |
262 | pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { | |
29967ef6 | 263 | ScalarInt::try_from_uint(i, size).map(Scalar::Int) |
dfeec247 XL |
264 | } |
265 | ||
b7449926 XL |
266 | #[inline] |
267 | pub fn from_uint(i: impl Into<u128>, size: Size) -> Self { | |
268 | let i = i.into(); | |
dfeec247 XL |
269 | Self::try_from_uint(i, size) |
270 | .unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits())) | |
dc9dc135 XL |
271 | } |
272 | ||
273 | #[inline] | |
274 | pub fn from_u8(i: u8) -> Self { | |
29967ef6 | 275 | Scalar::Int(i.into()) |
dc9dc135 XL |
276 | } |
277 | ||
278 | #[inline] | |
279 | pub fn from_u16(i: u16) -> Self { | |
29967ef6 | 280 | Scalar::Int(i.into()) |
dc9dc135 XL |
281 | } |
282 | ||
283 | #[inline] | |
284 | pub fn from_u32(i: u32) -> Self { | |
29967ef6 | 285 | Scalar::Int(i.into()) |
dc9dc135 XL |
286 | } |
287 | ||
288 | #[inline] | |
289 | pub fn from_u64(i: u64) -> Self { | |
29967ef6 | 290 | Scalar::Int(i.into()) |
ea8adc8c | 291 | } |
ea8adc8c | 292 | |
74b04a01 XL |
293 | #[inline] |
294 | pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { | |
295 | Self::from_uint(i, cx.data_layout().pointer_size) | |
296 | } | |
297 | ||
b7449926 | 298 | #[inline] |
dfeec247 | 299 | pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> { |
29967ef6 | 300 | ScalarInt::try_from_int(i, size).map(Scalar::Int) |
dfeec247 XL |
301 | } |
302 | ||
303 | #[inline] | |
304 | pub fn from_int(i: impl Into<i128>, size: Size) -> Self { | |
305 | let i = i.into(); | |
306 | Self::try_from_int(i, size) | |
307 | .unwrap_or_else(|| bug!("Signed value {:#x} does not fit in {} bits", i, size.bits())) | |
ea8adc8c XL |
308 | } |
309 | ||
ba9703b0 XL |
310 | #[inline] |
311 | pub fn from_i8(i: i8) -> Self { | |
312 | Self::from_int(i, Size::from_bits(8)) | |
313 | } | |
314 | ||
315 | #[inline] | |
316 | pub fn from_i16(i: i16) -> Self { | |
317 | Self::from_int(i, Size::from_bits(16)) | |
318 | } | |
319 | ||
320 | #[inline] | |
321 | pub fn from_i32(i: i32) -> Self { | |
322 | Self::from_int(i, Size::from_bits(32)) | |
323 | } | |
324 | ||
325 | #[inline] | |
326 | pub fn from_i64(i: i64) -> Self { | |
327 | Self::from_int(i, Size::from_bits(64)) | |
328 | } | |
329 | ||
74b04a01 XL |
330 | #[inline] |
331 | pub fn from_machine_isize(i: i64, cx: &impl HasDataLayout) -> Self { | |
332 | Self::from_int(i, cx.data_layout().pointer_size) | |
333 | } | |
334 | ||
b7449926 | 335 | #[inline] |
dc9dc135 | 336 | pub fn from_f32(f: Single) -> Self { |
29967ef6 | 337 | Scalar::Int(f.into()) |
ea8adc8c XL |
338 | } |
339 | ||
b7449926 | 340 | #[inline] |
dc9dc135 | 341 | pub fn from_f64(f: Double) -> Self { |
29967ef6 | 342 | Scalar::Int(f.into()) |
dc9dc135 XL |
343 | } |
344 | ||
416331ca XL |
345 | /// This is very rarely the method you want! You should dispatch on the type |
346 | /// and use `force_bits`/`assert_bits`/`force_ptr`/`assert_ptr`. | |
347 | /// This method only exists for the benefit of low-level memory operations | |
348 | /// as well as the implementation of the `force_*` methods. | |
dc9dc135 XL |
349 | #[inline] |
350 | pub fn to_bits_or_ptr( | |
351 | self, | |
352 | target_size: Size, | |
353 | cx: &impl HasDataLayout, | |
354 | ) -> Result<u128, Pointer<Tag>> { | |
74b04a01 | 355 | assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); |
dc9dc135 | 356 | match self { |
29967ef6 | 357 | Scalar::Int(int) => Ok(int.assert_bits(target_size)), |
dc9dc135 XL |
358 | Scalar::Ptr(ptr) => { |
359 | assert_eq!(target_size, cx.data_layout().pointer_size); | |
360 | Err(ptr) | |
361 | } | |
362 | } | |
ea8adc8c XL |
363 | } |
364 | ||
74b04a01 XL |
365 | /// This method is intentionally private! |
366 | /// It is just a helper for other methods in this file. | |
b7449926 | 367 | #[inline] |
74b04a01 XL |
368 | fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { |
369 | assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); | |
ea8adc8c | 370 | match self { |
29967ef6 XL |
371 | Scalar::Int(int) => int.to_bits(target_size).map_err(|size| { |
372 | err_ub!(ScalarSizeMismatch { | |
373 | target_size: target_size.bytes(), | |
374 | data_size: size.bytes(), | |
375 | }) | |
376 | .into() | |
377 | }), | |
416331ca | 378 | Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), |
ea8adc8c XL |
379 | } |
380 | } | |
381 | ||
416331ca XL |
382 | #[inline(always)] |
383 | pub fn assert_bits(self, target_size: Size) -> u128 { | |
e1599b0c | 384 | self.to_bits(target_size).expect("expected Raw bits but got a Pointer") |
416331ca XL |
385 | } |
386 | ||
29967ef6 XL |
387 | #[inline] |
388 | pub fn assert_int(self) -> ScalarInt { | |
389 | match self { | |
390 | Scalar::Ptr(_) => bug!("expected an int but got an abstract pointer"), | |
391 | Scalar::Int(int) => int, | |
392 | } | |
393 | } | |
394 | ||
b7449926 | 395 | #[inline] |
74b04a01 | 396 | pub fn assert_ptr(self) -> Pointer<Tag> { |
ea8adc8c | 397 | match self { |
74b04a01 | 398 | Scalar::Ptr(p) => p, |
29967ef6 | 399 | Scalar::Int { .. } => bug!("expected a Pointer but got Raw bits"), |
ea8adc8c XL |
400 | } |
401 | } | |
402 | ||
416331ca | 403 | /// Do not call this method! Dispatch based on the type instead. |
b7449926 | 404 | #[inline] |
94b46f34 | 405 | pub fn is_bits(self) -> bool { |
29967ef6 | 406 | matches!(self, Scalar::Int { .. }) |
ea8adc8c XL |
407 | } |
408 | ||
416331ca | 409 | /// Do not call this method! Dispatch based on the type instead. |
b7449926 | 410 | #[inline] |
ea8adc8c | 411 | pub fn is_ptr(self) -> bool { |
29967ef6 | 412 | matches!(self, Scalar::Ptr(_)) |
ea8adc8c XL |
413 | } |
414 | ||
dc9dc135 | 415 | pub fn to_bool(self) -> InterpResult<'tcx, bool> { |
ba9703b0 XL |
416 | let val = self.to_u8()?; |
417 | match val { | |
418 | 0 => Ok(false), | |
419 | 1 => Ok(true), | |
420 | _ => throw_ub!(InvalidBool(val)), | |
ea8adc8c XL |
421 | } |
422 | } | |
b7449926 | 423 | |
dc9dc135 | 424 | pub fn to_char(self) -> InterpResult<'tcx, char> { |
b7449926 | 425 | let val = self.to_u32()?; |
29967ef6 | 426 | match std::char::from_u32(val) { |
b7449926 | 427 | Some(c) => Ok(c), |
ba9703b0 | 428 | None => throw_ub!(InvalidChar(val)), |
b7449926 XL |
429 | } |
430 | } | |
431 | ||
dfeec247 XL |
432 | #[inline] |
433 | fn to_unsigned_with_bit_width(self, bits: u64) -> InterpResult<'static, u128> { | |
434 | let sz = Size::from_bits(bits); | |
435 | self.to_bits(sz) | |
436 | } | |
437 | ||
438 | /// Converts the scalar to produce an `u8`. Fails if the scalar is a pointer. | |
dc9dc135 | 439 | pub fn to_u8(self) -> InterpResult<'static, u8> { |
ba9703b0 | 440 | self.to_unsigned_with_bit_width(8).map(|v| u8::try_from(v).unwrap()) |
b7449926 XL |
441 | } |
442 | ||
dfeec247 XL |
443 | /// Converts the scalar to produce an `u16`. Fails if the scalar is a pointer. |
444 | pub fn to_u16(self) -> InterpResult<'static, u16> { | |
ba9703b0 | 445 | self.to_unsigned_with_bit_width(16).map(|v| u16::try_from(v).unwrap()) |
dfeec247 XL |
446 | } |
447 | ||
448 | /// Converts the scalar to produce an `u32`. Fails if the scalar is a pointer. | |
dc9dc135 | 449 | pub fn to_u32(self) -> InterpResult<'static, u32> { |
ba9703b0 | 450 | self.to_unsigned_with_bit_width(32).map(|v| u32::try_from(v).unwrap()) |
b7449926 XL |
451 | } |
452 | ||
dfeec247 | 453 | /// Converts the scalar to produce an `u64`. Fails if the scalar is a pointer. |
dc9dc135 | 454 | pub fn to_u64(self) -> InterpResult<'static, u64> { |
ba9703b0 | 455 | self.to_unsigned_with_bit_width(64).map(|v| u64::try_from(v).unwrap()) |
b7449926 XL |
456 | } |
457 | ||
1b1a35ee XL |
458 | /// Converts the scalar to produce an `u128`. Fails if the scalar is a pointer. |
459 | pub fn to_u128(self) -> InterpResult<'static, u128> { | |
460 | self.to_unsigned_with_bit_width(128) | |
461 | } | |
462 | ||
60c5eb7d | 463 | pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> { |
b7449926 | 464 | let b = self.to_bits(cx.data_layout().pointer_size)?; |
ba9703b0 | 465 | Ok(u64::try_from(b).unwrap()) |
b7449926 XL |
466 | } |
467 | ||
dfeec247 XL |
468 | #[inline] |
469 | fn to_signed_with_bit_width(self, bits: u64) -> InterpResult<'static, i128> { | |
470 | let sz = Size::from_bits(bits); | |
b7449926 | 471 | let b = self.to_bits(sz)?; |
29967ef6 | 472 | Ok(sz.sign_extend(b) as i128) |
b7449926 XL |
473 | } |
474 | ||
dfeec247 XL |
475 | /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. |
476 | pub fn to_i8(self) -> InterpResult<'static, i8> { | |
ba9703b0 | 477 | self.to_signed_with_bit_width(8).map(|v| i8::try_from(v).unwrap()) |
dfeec247 XL |
478 | } |
479 | ||
480 | /// Converts the scalar to produce an `i16`. Fails if the scalar is a pointer. | |
481 | pub fn to_i16(self) -> InterpResult<'static, i16> { | |
ba9703b0 | 482 | self.to_signed_with_bit_width(16).map(|v| i16::try_from(v).unwrap()) |
dfeec247 XL |
483 | } |
484 | ||
485 | /// Converts the scalar to produce an `i32`. Fails if the scalar is a pointer. | |
dc9dc135 | 486 | pub fn to_i32(self) -> InterpResult<'static, i32> { |
ba9703b0 | 487 | self.to_signed_with_bit_width(32).map(|v| i32::try_from(v).unwrap()) |
b7449926 XL |
488 | } |
489 | ||
dfeec247 | 490 | /// Converts the scalar to produce an `i64`. Fails if the scalar is a pointer. |
dc9dc135 | 491 | pub fn to_i64(self) -> InterpResult<'static, i64> { |
ba9703b0 | 492 | self.to_signed_with_bit_width(64).map(|v| i64::try_from(v).unwrap()) |
b7449926 XL |
493 | } |
494 | ||
1b1a35ee XL |
495 | /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer. |
496 | pub fn to_i128(self) -> InterpResult<'static, i128> { | |
497 | self.to_signed_with_bit_width(128) | |
498 | } | |
499 | ||
60c5eb7d | 500 | pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { |
dc9dc135 XL |
501 | let sz = cx.data_layout().pointer_size; |
502 | let b = self.to_bits(sz)?; | |
29967ef6 | 503 | let b = sz.sign_extend(b) as i128; |
ba9703b0 | 504 | Ok(i64::try_from(b).unwrap()) |
b7449926 XL |
505 | } |
506 | ||
507 | #[inline] | |
dc9dc135 XL |
508 | pub fn to_f32(self) -> InterpResult<'static, Single> { |
509 | // Going through `u32` to check size and truncation. | |
ba9703b0 | 510 | Ok(Single::from_bits(self.to_u32()?.into())) |
b7449926 XL |
511 | } |
512 | ||
513 | #[inline] | |
dc9dc135 XL |
514 | pub fn to_f64(self) -> InterpResult<'static, Double> { |
515 | // Going through `u64` to check size and truncation. | |
ba9703b0 | 516 | Ok(Double::from_bits(self.to_u64()?.into())) |
b7449926 XL |
517 | } |
518 | } | |
519 | ||
0bf4aa26 | 520 | impl<Tag> From<Pointer<Tag>> for Scalar<Tag> { |
b7449926 | 521 | #[inline(always)] |
0bf4aa26 | 522 | fn from(ptr: Pointer<Tag>) -> Self { |
b7449926 XL |
523 | Scalar::Ptr(ptr) |
524 | } | |
525 | } | |
a1dfa0c6 | 526 | |
6a06907d XL |
527 | impl<Tag> From<ScalarInt> for Scalar<Tag> { |
528 | #[inline(always)] | |
529 | fn from(ptr: ScalarInt) -> Self { | |
530 | Scalar::Int(ptr) | |
531 | } | |
532 | } | |
533 | ||
3dfed10e | 534 | #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] |
f9f354fc XL |
535 | pub enum ScalarMaybeUninit<Tag = ()> { |
536 | Scalar(Scalar<Tag>), | |
537 | Uninit, | |
a1dfa0c6 XL |
538 | } |
539 | ||
6a06907d | 540 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
1b1a35ee XL |
541 | static_assert_size!(ScalarMaybeUninit, 24); |
542 | ||
f9f354fc | 543 | impl<Tag> From<Scalar<Tag>> for ScalarMaybeUninit<Tag> { |
a1dfa0c6 XL |
544 | #[inline(always)] |
545 | fn from(s: Scalar<Tag>) -> Self { | |
f9f354fc | 546 | ScalarMaybeUninit::Scalar(s) |
a1dfa0c6 XL |
547 | } |
548 | } | |
549 | ||
f9f354fc | 550 | impl<Tag> From<Pointer<Tag>> for ScalarMaybeUninit<Tag> { |
60c5eb7d XL |
551 | #[inline(always)] |
552 | fn from(s: Pointer<Tag>) -> Self { | |
f9f354fc | 553 | ScalarMaybeUninit::Scalar(s.into()) |
60c5eb7d XL |
554 | } |
555 | } | |
556 | ||
f9f354fc XL |
557 | // We want the `Debug` output to be readable as it is used by `derive(Debug)` for |
558 | // all the Miri types. | |
559 | impl<Tag: fmt::Debug> fmt::Debug for ScalarMaybeUninit<Tag> { | |
a1dfa0c6 XL |
560 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
561 | match self { | |
f9f354fc XL |
562 | ScalarMaybeUninit::Uninit => write!(f, "<uninitialized>"), |
563 | ScalarMaybeUninit::Scalar(s) => write!(f, "{:?}", s), | |
a1dfa0c6 XL |
564 | } |
565 | } | |
566 | } | |
567 | ||
f9f354fc | 568 | impl<Tag: fmt::Debug> fmt::Display for ScalarMaybeUninit<Tag> { |
dc9dc135 | 569 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
a1dfa0c6 | 570 | match self { |
f9f354fc XL |
571 | ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"), |
572 | ScalarMaybeUninit::Scalar(s) => write!(f, "{}", s), | |
a1dfa0c6 XL |
573 | } |
574 | } | |
575 | } | |
576 | ||
f9f354fc | 577 | impl<'tcx, Tag> ScalarMaybeUninit<Tag> { |
dc9dc135 XL |
578 | /// Erase the tag from the scalar, if any. |
579 | /// | |
580 | /// Used by error reporting code to avoid having the error type depend on `Tag`. | |
a1dfa0c6 | 581 | #[inline] |
f9f354fc | 582 | pub fn erase_tag(self) -> ScalarMaybeUninit { |
a1dfa0c6 | 583 | match self { |
f9f354fc XL |
584 | ScalarMaybeUninit::Scalar(s) => ScalarMaybeUninit::Scalar(s.erase_tag()), |
585 | ScalarMaybeUninit::Uninit => ScalarMaybeUninit::Uninit, | |
a1dfa0c6 XL |
586 | } |
587 | } | |
588 | ||
589 | #[inline] | |
3dfed10e | 590 | pub fn check_init(self) -> InterpResult<'static, Scalar<Tag>> { |
a1dfa0c6 | 591 | match self { |
f9f354fc XL |
592 | ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), |
593 | ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), | |
a1dfa0c6 XL |
594 | } |
595 | } | |
596 | ||
a1dfa0c6 | 597 | #[inline(always)] |
dc9dc135 | 598 | pub fn to_bool(self) -> InterpResult<'tcx, bool> { |
3dfed10e | 599 | self.check_init()?.to_bool() |
a1dfa0c6 XL |
600 | } |
601 | ||
602 | #[inline(always)] | |
dc9dc135 | 603 | pub fn to_char(self) -> InterpResult<'tcx, char> { |
3dfed10e | 604 | self.check_init()?.to_char() |
a1dfa0c6 XL |
605 | } |
606 | ||
607 | #[inline(always)] | |
dc9dc135 | 608 | pub fn to_f32(self) -> InterpResult<'tcx, Single> { |
3dfed10e | 609 | self.check_init()?.to_f32() |
a1dfa0c6 XL |
610 | } |
611 | ||
612 | #[inline(always)] | |
dc9dc135 | 613 | pub fn to_f64(self) -> InterpResult<'tcx, Double> { |
3dfed10e | 614 | self.check_init()?.to_f64() |
a1dfa0c6 XL |
615 | } |
616 | ||
617 | #[inline(always)] | |
dc9dc135 | 618 | pub fn to_u8(self) -> InterpResult<'tcx, u8> { |
3dfed10e | 619 | self.check_init()?.to_u8() |
a1dfa0c6 XL |
620 | } |
621 | ||
74b04a01 XL |
622 | #[inline(always)] |
623 | pub fn to_u16(self) -> InterpResult<'tcx, u16> { | |
3dfed10e | 624 | self.check_init()?.to_u16() |
74b04a01 XL |
625 | } |
626 | ||
a1dfa0c6 | 627 | #[inline(always)] |
dc9dc135 | 628 | pub fn to_u32(self) -> InterpResult<'tcx, u32> { |
3dfed10e | 629 | self.check_init()?.to_u32() |
a1dfa0c6 XL |
630 | } |
631 | ||
632 | #[inline(always)] | |
dc9dc135 | 633 | pub fn to_u64(self) -> InterpResult<'tcx, u64> { |
3dfed10e | 634 | self.check_init()?.to_u64() |
a1dfa0c6 XL |
635 | } |
636 | ||
637 | #[inline(always)] | |
60c5eb7d | 638 | pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { |
3dfed10e | 639 | self.check_init()?.to_machine_usize(cx) |
a1dfa0c6 XL |
640 | } |
641 | ||
642 | #[inline(always)] | |
dc9dc135 | 643 | pub fn to_i8(self) -> InterpResult<'tcx, i8> { |
3dfed10e | 644 | self.check_init()?.to_i8() |
a1dfa0c6 | 645 | } |
74b04a01 XL |
646 | |
647 | #[inline(always)] | |
648 | pub fn to_i16(self) -> InterpResult<'tcx, i16> { | |
3dfed10e | 649 | self.check_init()?.to_i16() |
74b04a01 | 650 | } |
a1dfa0c6 XL |
651 | |
652 | #[inline(always)] | |
dc9dc135 | 653 | pub fn to_i32(self) -> InterpResult<'tcx, i32> { |
3dfed10e | 654 | self.check_init()?.to_i32() |
a1dfa0c6 XL |
655 | } |
656 | ||
657 | #[inline(always)] | |
dc9dc135 | 658 | pub fn to_i64(self) -> InterpResult<'tcx, i64> { |
3dfed10e | 659 | self.check_init()?.to_i64() |
a1dfa0c6 XL |
660 | } |
661 | ||
662 | #[inline(always)] | |
60c5eb7d | 663 | pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { |
3dfed10e | 664 | self.check_init()?.to_machine_isize(cx) |
a1dfa0c6 XL |
665 | } |
666 | } | |
667 | ||
e74abb32 XL |
668 | /// Gets the bytes of a constant slice value. |
669 | pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] { | |
670 | if let ConstValue::Slice { data, start, end } = val { | |
671 | let len = end - start; | |
672 | data.get_bytes( | |
673 | cx, | |
674 | // invent a pointer, only the offset is relevant anyway | |
ba9703b0 XL |
675 | Pointer::new(AllocId(0), Size::from_bytes(start)), |
676 | Size::from_bytes(len), | |
dfeec247 XL |
677 | ) |
678 | .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)) | |
e74abb32 XL |
679 | } else { |
680 | bug!("expected const slice, but found another const value"); | |
681 | } | |
682 | } |