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