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