rustc_middle/mir/interpret/
value.rs1use std::fmt;
2
3use either::{Either, Left, Right};
4use rustc_abi::{HasDataLayout, Size};
5use rustc_apfloat::Float;
6use rustc_apfloat::ieee::{Double, Half, Quad, Single};
7use rustc_macros::{StableHash, TyDecodable, TyEncodable};
8
9use super::{
10 AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance, interp_ok,
11};
12use crate::ty::ScalarInt;
13
14#[derive(#[automatically_derived]
impl<Prov: ::core::clone::Clone> ::core::clone::Clone for Scalar<Prov> {
#[inline]
fn clone(&self) -> Scalar<Prov> {
match self {
Scalar::Int(__self_0) =>
Scalar::Int(::core::clone::Clone::clone(__self_0)),
Scalar::Ptr(__self_0, __self_1) =>
Scalar::Ptr(::core::clone::Clone::clone(__self_0),
::core::clone::Clone::clone(__self_1)),
}
}
}Clone, #[automatically_derived]
impl<Prov: ::core::marker::Copy> ::core::marker::Copy for Scalar<Prov> { }Copy, #[automatically_derived]
impl<Prov: ::core::cmp::Eq> ::core::cmp::Eq for Scalar<Prov> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<ScalarInt>;
let _: ::core::cmp::AssertParamIsEq<Pointer<Prov>>;
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}Eq, #[automatically_derived]
impl<Prov: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Scalar<Prov> {
#[inline]
fn eq(&self, other: &Scalar<Prov>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(Scalar::Int(__self_0), Scalar::Int(__arg1_0)) =>
__self_0 == __arg1_0,
(Scalar::Ptr(__self_0, __self_1),
Scalar::Ptr(__arg1_0, __arg1_1)) =>
__self_1 == __arg1_1 && __self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, const _: () =
{
impl<'tcx, Prov, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for Scalar<Prov> where
Pointer<Prov>: ::rustc_serialize::Encodable<__E> {
fn encode(&self, __encoder: &mut __E) {
let disc =
match *self {
Scalar::Int(ref __binding_0) => { 0usize }
Scalar::Ptr(ref __binding_0, ref __binding_1) => { 1usize }
};
::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
match *self {
Scalar::Int(ref __binding_0) => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
}
Scalar::Ptr(ref __binding_0, ref __binding_1) => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
}
}
}
}
};TyEncodable, const _: () =
{
impl<'tcx, Prov, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for Scalar<Prov> where
Pointer<Prov>: ::rustc_serialize::Decodable<__D> {
fn decode(__decoder: &mut __D) -> Self {
match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
{
0usize => {
Scalar::Int(::rustc_serialize::Decodable::decode(__decoder))
}
1usize => {
Scalar::Ptr(::rustc_serialize::Decodable::decode(__decoder),
::rustc_serialize::Decodable::decode(__decoder))
}
n => {
::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `Scalar`, expected 0..2, actual {0}",
n));
}
}
}
}
};TyDecodable, #[automatically_derived]
impl<Prov: ::core::hash::Hash> ::core::hash::Hash for Scalar<Prov> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state);
match self {
Scalar::Int(__self_0) =>
::core::hash::Hash::hash(__self_0, state),
Scalar::Ptr(__self_0, __self_1) => {
::core::hash::Hash::hash(__self_0, state);
::core::hash::Hash::hash(__self_1, state)
}
}
}
}Hash)]
22#[derive(const _: () =
{
impl<Prov> ::rustc_data_structures::stable_hash::StableHash for
Scalar<Prov> where
Prov: ::rustc_data_structures::stable_hash::StableHash {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
match *self {
Scalar::Int(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
Scalar::Ptr(ref __binding_0, ref __binding_1) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
23pub enum Scalar<Prov = CtfeProvenance> {
24 Int(ScalarInt),
26
27 Ptr(Pointer<Prov>, u8),
33}
34
35#[cfg(target_pointer_width = "64")]
36const _: [(); 24] = [(); ::std::mem::size_of::<Scalar>()];rustc_data_structures::static_assert_size!(Scalar, 24);
37
38impl<Prov: Provenance> fmt::Debug for Scalar<Prov> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 Scalar::Ptr(ptr, _size) => f.write_fmt(format_args!("{0:?}", ptr))write!(f, "{ptr:?}"),
44 Scalar::Int(int) => f.write_fmt(format_args!("{0:?}", int))write!(f, "{int:?}"),
45 }
46 }
47}
48
49impl<Prov: Provenance> fmt::Display for Scalar<Prov> {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 Scalar::Ptr(ptr, _size) => f.write_fmt(format_args!("pointer to {0:?}", ptr))write!(f, "pointer to {ptr:?}"),
53 Scalar::Int(int) => f.write_fmt(format_args!("{0}", int))write!(f, "{int}"),
54 }
55 }
56}
57
58impl<Prov: Provenance> fmt::LowerHex for Scalar<Prov> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 Scalar::Ptr(ptr, _size) => f.write_fmt(format_args!("pointer to {0:?}", ptr))write!(f, "pointer to {ptr:?}"),
62 Scalar::Int(int) => f.write_fmt(format_args!("{0:#x}", int))write!(f, "{int:#x}"),
63 }
64 }
65}
66
67impl<Prov> From<Half> for Scalar<Prov> {
68 #[inline(always)]
69 fn from(f: Half) -> Self {
70 Scalar::from_f16(f)
71 }
72}
73
74impl<Prov> From<Single> for Scalar<Prov> {
75 #[inline(always)]
76 fn from(f: Single) -> Self {
77 Scalar::from_f32(f)
78 }
79}
80
81impl<Prov> From<Double> for Scalar<Prov> {
82 #[inline(always)]
83 fn from(f: Double) -> Self {
84 Scalar::from_f64(f)
85 }
86}
87
88impl<Prov> From<Quad> for Scalar<Prov> {
89 #[inline(always)]
90 fn from(f: Quad) -> Self {
91 Scalar::from_f128(f)
92 }
93}
94
95impl<Prov> From<ScalarInt> for Scalar<Prov> {
96 #[inline(always)]
97 fn from(ptr: ScalarInt) -> Self {
98 Scalar::Int(ptr)
99 }
100}
101
102impl<Prov> Scalar<Prov> {
103 #[inline(always)]
104 pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
105 Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap())
106 }
107
108 pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
111 match ptr.into_raw_parts() {
112 (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx),
113 (None, offset) => {
114 Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap())
115 }
116 }
117 }
118
119 #[inline]
120 pub fn null_ptr(cx: &impl HasDataLayout) -> Self {
121 Scalar::Int(ScalarInt::null(cx.pointer_size()))
122 }
123
124 #[inline]
125 pub fn from_bool(b: bool) -> Self {
126 Scalar::Int(b.into())
127 }
128
129 #[inline]
130 pub fn from_char(c: char) -> Self {
131 Scalar::Int(c.into())
132 }
133
134 #[inline]
135 pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
136 let i = i.into();
137 ScalarInt::try_from_uint(i, size)
138 .unwrap_or_else(|| crate::util::bug::bug_fmt(format_args!("Unsigned value {0:#x} does not fit in {1} bits",
i, size.bits()))bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()))
139 .into()
140 }
141
142 #[inline]
143 pub fn from_u8(i: u8) -> Self {
144 Scalar::Int(i.into())
145 }
146
147 #[inline]
148 pub fn from_u16(i: u16) -> Self {
149 Scalar::Int(i.into())
150 }
151
152 #[inline]
153 pub fn from_u32(i: u32) -> Self {
154 Scalar::Int(i.into())
155 }
156
157 #[inline]
158 pub fn from_u64(i: u64) -> Self {
159 Scalar::Int(i.into())
160 }
161
162 #[inline]
163 pub fn from_u128(i: u128) -> Self {
164 Scalar::Int(i.into())
165 }
166
167 #[inline]
168 pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
169 Self::from_uint(i, cx.data_layout().pointer_offset())
170 }
171
172 #[inline]
173 pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
174 let i = i.into();
175 ScalarInt::try_from_int(i, size)
176 .unwrap_or_else(|| crate::util::bug::bug_fmt(format_args!("Signed value {0:#x} does not fit in {1} bits",
i, size.bits()))bug!("Signed value {:#x} does not fit in {} bits", i, size.bits()))
177 .into()
178 }
179
180 #[inline]
181 pub fn from_i8(i: i8) -> Self {
182 Self::Int(i.into())
183 }
184
185 #[inline]
186 pub fn from_i16(i: i16) -> Self {
187 Self::Int(i.into())
188 }
189
190 #[inline]
191 pub fn from_i32(i: i32) -> Self {
192 Self::Int(i.into())
193 }
194
195 #[inline]
196 pub fn from_i64(i: i64) -> Self {
197 Self::Int(i.into())
198 }
199
200 #[inline]
201 pub fn from_i128(i: i128) -> Self {
202 Self::Int(i.into())
203 }
204
205 #[inline]
206 pub fn from_target_isize(i: i64, cx: &impl HasDataLayout) -> Self {
207 Self::from_int(i, cx.data_layout().pointer_offset())
208 }
209
210 #[inline]
211 pub fn from_f16(f: Half) -> Self {
212 Scalar::Int(f.into())
213 }
214
215 #[inline]
216 pub fn from_f32(f: Single) -> Self {
217 Scalar::Int(f.into())
218 }
219
220 #[inline]
221 pub fn from_f64(f: Double) -> Self {
222 Scalar::Int(f.into())
223 }
224
225 #[inline]
226 pub fn from_f128(f: Quad) -> Self {
227 Scalar::Int(f.into())
228 }
229
230 #[inline]
239 pub fn to_bits_or_ptr_internal(self, target_size: Size) -> Either<u128, Pointer<Prov>> {
240 {
match (&(target_size.bytes()), &(0)) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("you should never look at the bits of a ZST")));
}
}
}
};assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
241 match self {
242 Scalar::Int(int) => Left(int.to_bits(target_size)),
243 Scalar::Ptr(ptr, sz) => {
244 {
match (&target_size.bytes(), &u64::from(sz)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("Scalar is a pointer but expected size {0}",
target_size.bytes())));
}
}
}
};assert_eq!(
245 target_size.bytes(),
246 u64::from(sz),
247 "Scalar is a pointer but expected size {}",
248 target_size.bytes()
249 );
250 Right(ptr)
251 }
252 }
253 }
254
255 #[inline]
256 pub fn size(self) -> Size {
257 match self {
258 Scalar::Int(int) => int.size(),
259 Scalar::Ptr(_ptr, sz) => Size::from_bytes(sz),
260 }
261 }
262}
263
264impl<'tcx, Prov: Provenance> Scalar<Prov> {
265 pub fn to_pointer(self, cx: &impl HasDataLayout) -> Pointer<Option<Prov>> {
266 match self.to_bits_or_ptr_internal(cx.pointer_size()) {
267 Right(ptr) => ptr.into(),
268 Left(bits) => {
269 let addr = u64::try_from(bits).unwrap();
270 Pointer::without_provenance(addr)
271 }
272 }
273 }
274
275 #[inline]
285 pub fn try_to_scalar_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
286 match self {
287 Scalar::Int(int) => Ok(int),
288 Scalar::Ptr(ptr, sz) => {
289 if Prov::OFFSET_IS_ADDR {
290 Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
291 } else {
292 let (prov, offset) = ptr.into_raw_parts();
294 Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz))
296 }
297 }
298 }
299 }
300
301 pub fn clear_provenance(&mut self) -> InterpResult<'tcx> {
302 if #[allow(non_exhaustive_omitted_patterns)] match self {
Scalar::Ptr(..) => true,
_ => false,
}matches!(self, Scalar::Ptr(..)) {
303 *self = self.to_scalar_int()?.into();
304 }
305 interp_ok(())
306 }
307
308 #[inline(always)]
309 pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> {
310 self.try_to_scalar_int().map_err(|_| crate::mir::interpret::InterpErrorKind::Unsupported(crate::mir::interpret::UnsupportedOpInfo::ReadPointerAsInt(None))err_unsup!(ReadPointerAsInt(None))).into()
311 }
312
313 #[inline(always)]
314 #[cfg_attr(debug_assertions, track_caller)] pub fn assert_scalar_int(self) -> ScalarInt {
316 self.try_to_scalar_int().expect("got a pointer where a ScalarInt was expected")
317 }
318
319 #[inline]
322 pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
323 {
match (&(target_size.bytes()), &(0)) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = ::core::panicking::AssertKind::Ne;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("you should never look at the bits of a ZST")));
}
}
}
};assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
324 interp_ok(self.to_scalar_int()?.to_bits(target_size))
325 }
326
327 pub fn to_bool(self) -> InterpResult<'tcx, bool> {
328 let val = self.to_u8()?;
329 match val {
330 0 => interp_ok(false),
331 1 => interp_ok(true),
332 _ => do yeet crate::mir::interpret::InterpErrorKind::UndefinedBehavior(crate::mir::interpret::UndefinedBehaviorInfo::InvalidBool(val))throw_ub!(InvalidBool(val)),
333 }
334 }
335
336 pub fn to_char(self) -> InterpResult<'tcx, char> {
337 let val = self.to_u32()?;
338 match std::char::from_u32(val) {
339 Some(c) => interp_ok(c),
340 None => do yeet crate::mir::interpret::InterpErrorKind::UndefinedBehavior(crate::mir::interpret::UndefinedBehaviorInfo::InvalidChar(val))throw_ub!(InvalidChar(val)),
341 }
342 }
343
344 #[inline]
347 pub fn to_uint(self, size: Size) -> InterpResult<'tcx, u128> {
348 self.to_bits(size)
349 }
350
351 pub fn to_u8(self) -> InterpResult<'tcx, u8> {
353 self.to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
354 }
355
356 pub fn to_u16(self) -> InterpResult<'tcx, u16> {
358 self.to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
359 }
360
361 pub fn to_u32(self) -> InterpResult<'tcx, u32> {
363 self.to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
364 }
365
366 pub fn to_u64(self) -> InterpResult<'tcx, u64> {
368 self.to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
369 }
370
371 pub fn to_u128(self) -> InterpResult<'tcx, u128> {
373 self.to_uint(Size::from_bits(128))
374 }
375
376 pub fn to_target_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
379 let b = self.to_uint(cx.data_layout().pointer_size())?;
380 interp_ok(u64::try_from(b).unwrap())
381 }
382
383 #[inline]
386 pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> {
387 let b = self.to_bits(size)?;
388 interp_ok(size.sign_extend(b))
389 }
390
391 pub fn to_i8(self) -> InterpResult<'tcx, i8> {
393 self.to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
394 }
395
396 pub fn to_i16(self) -> InterpResult<'tcx, i16> {
398 self.to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
399 }
400
401 pub fn to_i32(self) -> InterpResult<'tcx, i32> {
403 self.to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
404 }
405
406 pub fn to_i64(self) -> InterpResult<'tcx, i64> {
408 self.to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
409 }
410
411 pub fn to_i128(self) -> InterpResult<'tcx, i128> {
413 self.to_int(Size::from_bits(128))
414 }
415
416 pub fn to_target_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
419 let b = self.to_int(cx.data_layout().pointer_size())?;
420 interp_ok(i64::try_from(b).unwrap())
421 }
422
423 #[inline]
424 pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
425 interp_ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
427 }
428
429 #[inline]
430 pub fn to_f16(self) -> InterpResult<'tcx, Half> {
431 self.to_float()
432 }
433
434 #[inline]
435 pub fn to_f32(self) -> InterpResult<'tcx, Single> {
436 self.to_float()
437 }
438
439 #[inline]
440 pub fn to_f64(self) -> InterpResult<'tcx, Double> {
441 self.to_float()
442 }
443
444 #[inline]
445 pub fn to_f128(self) -> InterpResult<'tcx, Quad> {
446 self.to_float()
447 }
448}