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