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