]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/value.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / value.rs
CommitLineData
6a06907d 1use std::convert::{TryFrom, TryInto};
ba9703b0
XL
2use std::fmt;
3
dfeec247
XL
4use rustc_apfloat::{
5 ieee::{Double, Single},
6 Float,
7};
532ac7d7 8use rustc_macros::HashStable;
ba9703b0 9use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
ea8adc8c 10
6a06907d 11use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
ea8adc8c 12
29967ef6 13use 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 17pub 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 28pub 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 48static_assert_size!(ConstValue<'_>, 32);
9fa01778 49
6a06907d
XL
50impl From<Scalar> for ConstValue<'tcx> {
51 fn from(s: Scalar) -> Self {
52 Self::Scalar(s)
53 }
54}
55
56impl<'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
71impl<'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 125pub 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 136static_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.
140impl<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 149impl<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
158impl<Tag> From<Single> for Scalar<Tag> {
159 #[inline(always)]
160 fn from(f: Single) -> Self {
161 Scalar::from_f32(f)
162 }
163}
164
165impl<Tag> From<Double> for Scalar<Tag> {
166 #[inline(always)]
167 fn from(f: Double) -> Self {
168 Scalar::from_f64(f)
169 }
170}
171
172impl 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
185impl<'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 520impl<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
527impl<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
535pub 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
541static_assert_size!(ScalarMaybeUninit, 24);
542
f9f354fc 543impl<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 550impl<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.
559impl<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 568impl<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 577impl<'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.
669pub 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}