1 use rustc_apfloat
::ieee
::{Double, Single}
;
2 use rustc_apfloat
::Float
;
3 use rustc_serialize
::{Decodable, Decoder, Encodable, Encoder}
;
4 use rustc_target
::abi
::Size
;
5 use std
::convert
::{TryFrom, TryInto}
;
10 #[derive(Copy, Clone)]
11 /// A type for representing any integer. Only used for printing.
13 /// The "untyped" variant of `ConstInt`.
15 /// Whether the value is of a signed integer type.
17 /// Whether the value is a `usize` or `isize` type.
18 is_ptr_sized_integral
: bool
,
22 pub fn new(int
: ScalarInt
, signed
: bool
, is_ptr_sized_integral
: bool
) -> Self {
23 Self { int, signed, is_ptr_sized_integral }
27 impl std
::fmt
::Debug
for ConstInt
{
28 fn fmt(&self, fmt
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
29 let Self { int, signed, is_ptr_sized_integral }
= *self;
30 let size
= int
.size().bytes();
33 let bit_size
= size
* 8;
34 let min
= 1u128 << (bit_size
- 1);
37 match (size
, is_ptr_sized_integral
) {
38 (_
, true) => write
!(fmt
, "isize::MIN"),
39 (1, _
) => write
!(fmt
, "i8::MIN"),
40 (2, _
) => write
!(fmt
, "i16::MIN"),
41 (4, _
) => write
!(fmt
, "i32::MIN"),
42 (8, _
) => write
!(fmt
, "i64::MIN"),
43 (16, _
) => write
!(fmt
, "i128::MIN"),
44 _
=> bug
!("ConstInt 0x{:x} with size = {} and signed = {}", raw
, size
, signed
),
46 } else if raw
== max
{
47 match (size
, is_ptr_sized_integral
) {
48 (_
, true) => write
!(fmt
, "isize::MAX"),
49 (1, _
) => write
!(fmt
, "i8::MAX"),
50 (2, _
) => write
!(fmt
, "i16::MAX"),
51 (4, _
) => write
!(fmt
, "i32::MAX"),
52 (8, _
) => write
!(fmt
, "i64::MAX"),
53 (16, _
) => write
!(fmt
, "i128::MAX"),
54 _
=> bug
!("ConstInt 0x{:x} with size = {} and signed = {}", raw
, size
, signed
),
58 1 => write
!(fmt
, "{}", raw
as i8)?
,
59 2 => write
!(fmt
, "{}", raw
as i16)?
,
60 4 => write
!(fmt
, "{}", raw
as i32)?
,
61 8 => write
!(fmt
, "{}", raw
as i64)?
,
62 16 => write
!(fmt
, "{}", raw
as i128
)?
,
63 _
=> bug
!("ConstInt 0x{:x} with size = {} and signed = {}", raw
, size
, signed
),
66 match (size
, is_ptr_sized_integral
) {
67 (_
, true) => write
!(fmt
, "_isize")?
,
68 (1, _
) => write
!(fmt
, "_i8")?
,
69 (2, _
) => write
!(fmt
, "_i16")?
,
70 (4, _
) => write
!(fmt
, "_i32")?
,
71 (8, _
) => write
!(fmt
, "_i64")?
,
72 (16, _
) => write
!(fmt
, "_i128")?
,
79 let max
= Size
::from_bytes(size
).truncate(u128
::MAX
);
81 match (size
, is_ptr_sized_integral
) {
82 (_
, true) => write
!(fmt
, "usize::MAX"),
83 (1, _
) => write
!(fmt
, "u8::MAX"),
84 (2, _
) => write
!(fmt
, "u16::MAX"),
85 (4, _
) => write
!(fmt
, "u32::MAX"),
86 (8, _
) => write
!(fmt
, "u64::MAX"),
87 (16, _
) => write
!(fmt
, "u128::MAX"),
88 _
=> bug
!("ConstInt 0x{:x} with size = {} and signed = {}", raw
, size
, signed
),
92 1 => write
!(fmt
, "{}", raw
as u8)?
,
93 2 => write
!(fmt
, "{}", raw
as u16)?
,
94 4 => write
!(fmt
, "{}", raw
as u32)?
,
95 8 => write
!(fmt
, "{}", raw
as u64)?
,
96 16 => write
!(fmt
, "{}", raw
as u128
)?
,
97 _
=> bug
!("ConstInt 0x{:x} with size = {} and signed = {}", raw
, size
, signed
),
100 match (size
, is_ptr_sized_integral
) {
101 (_
, true) => write
!(fmt
, "_usize")?
,
102 (1, _
) => write
!(fmt
, "_u8")?
,
103 (2, _
) => write
!(fmt
, "_u16")?
,
104 (4, _
) => write
!(fmt
, "_u32")?
,
105 (8, _
) => write
!(fmt
, "_u64")?
,
106 (16, _
) => write
!(fmt
, "_u128")?
,
116 /// The raw bytes of a simple value.
118 /// This is a packed struct in order to allow this type to be optimally embedded in enums
120 #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
122 pub struct ScalarInt
{
123 /// The first `size` bytes of `data` are the value.
124 /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
129 // Cannot derive these, as the derives take references to the fields, and we
130 // can't take references to fields of packed structs.
131 impl<CTX
> crate::ty
::HashStable
<CTX
> for ScalarInt
{
132 fn hash_stable(&self, hcx
: &mut CTX
, hasher
: &mut crate::ty
::StableHasher
) {
133 // Using a block `{self.data}` here to force a copy instead of using `self.data`
134 // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
135 // Since `Self` is a packed struct, that would create a possibly unaligned reference,
137 { self.data }
.hash_stable(hcx
, hasher
);
138 self.size
.hash_stable(hcx
, hasher
);
142 impl<S
: Encoder
> Encodable
<S
> for ScalarInt
{
143 fn encode(&self, s
: &mut S
) {
144 s
.emit_u128(self.data
);
145 s
.emit_u8(self.size
);
149 impl<D
: Decoder
> Decodable
<D
> for ScalarInt
{
150 fn decode(d
: &mut D
) -> ScalarInt
{
151 ScalarInt { data: d.read_u128(), size: d.read_u8() }
156 pub const TRUE
: ScalarInt
= ScalarInt { data: 1_u128, size: 1 }
;
158 pub const FALSE
: ScalarInt
= ScalarInt { data: 0_u128, size: 1 }
;
160 pub const ZST
: ScalarInt
= ScalarInt { data: 0_u128, size: 0 }
;
163 pub fn size(self) -> Size
{
164 Size
::from_bytes(self.size
)
167 /// Make sure the `data` fits in `size`.
168 /// This is guaranteed by all constructors here, but having had this check saved us from
169 /// bugs many times in the past, so keeping it around is definitely worth it.
171 fn check_data(self) {
172 // Using a block `{self.data}` here to force a copy instead of using `self.data`
173 // directly, because `debug_assert_eq` takes references to its arguments and formatting
174 // arguments and would thus borrow `self.data`. Since `Self`
175 // is a packed struct, that would create a possibly unaligned reference, which
178 self.size().truncate(self.data
),
180 "Scalar value {:#x} exceeds size of {} bytes",
187 pub fn null(size
: Size
) -> Self {
188 Self { data: 0, size: size.bytes() as u8 }
192 pub fn is_null(self) -> bool
{
197 pub fn try_from_uint(i
: impl Into
<u128
>, size
: Size
) -> Option
<Self> {
199 if size
.truncate(data
) == data
{
200 Some(Self { data, size: size.bytes() as u8 }
)
207 pub fn try_from_int(i
: impl Into
<i128
>, size
: Size
) -> Option
<Self> {
209 // `into` performed sign extension, we have to truncate
210 let truncated
= size
.truncate(i
as u128
);
211 if size
.sign_extend(truncated
) as i128
== i
{
212 Some(Self { data: truncated, size: size.bytes() as u8 }
)
219 pub fn assert_bits(self, target_size
: Size
) -> u128
{
220 self.to_bits(target_size
).unwrap_or_else(|size
| {
221 bug
!("expected int of size {}, but got size {}", target_size
.bytes(), size
.bytes())
226 pub fn to_bits(self, target_size
: Size
) -> Result
<u128
, Size
> {
227 assert_ne
!(target_size
.bytes(), 0, "you should never look at the bits of a ZST");
228 if target_size
.bytes() == u64::from(self.size
) {
237 pub fn try_to_machine_usize
<'tcx
>(&self, tcx
: TyCtxt
<'tcx
>) -> Result
<u64, Size
> {
238 Ok(self.to_bits(tcx
.data_layout
.pointer_size
)?
as u64)
241 /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
242 /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
243 /// `ScalarInt`s size in that case.
245 pub fn try_to_uint(self, size
: Size
) -> Result
<u128
, Size
> {
249 // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
250 // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
253 pub fn try_to_u8(self) -> Result
<u8, Size
> {
254 self.to_bits(Size
::from_bits(8)).map(|v
| u8::try_from(v
).unwrap())
257 /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
258 /// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
261 pub fn try_to_u16(self) -> Result
<u16, Size
> {
262 self.to_bits(Size
::from_bits(16)).map(|v
| u16::try_from(v
).unwrap())
265 /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
266 /// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
269 pub fn try_to_u32(self) -> Result
<u32, Size
> {
270 self.to_bits(Size
::from_bits(32)).map(|v
| u32::try_from(v
).unwrap())
273 /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
274 /// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
277 pub fn try_to_u64(self) -> Result
<u64, Size
> {
278 self.to_bits(Size
::from_bits(64)).map(|v
| u64::try_from(v
).unwrap())
281 /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
282 /// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
285 pub fn try_to_u128(self) -> Result
<u128
, Size
> {
286 self.to_bits(Size
::from_bits(128))
289 /// Tries to convert the `ScalarInt` to a signed integer of the given size.
290 /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the
291 /// `ScalarInt`s size in that case.
293 pub fn try_to_int(self, size
: Size
) -> Result
<i128
, Size
> {
294 let b
= self.to_bits(size
)?
;
295 Ok(size
.sign_extend(b
) as i128
)
298 /// Tries to convert the `ScalarInt` to i8.
299 /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }`
300 /// and returns the `ScalarInt`s size in that case.
301 pub fn try_to_i8(self) -> Result
<i8, Size
> {
302 self.try_to_int(Size
::from_bits(8)).map(|v
| i8::try_from(v
).unwrap())
305 /// Tries to convert the `ScalarInt` to i16.
306 /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }`
307 /// and returns the `ScalarInt`s size in that case.
308 pub fn try_to_i16(self) -> Result
<i16, Size
> {
309 self.try_to_int(Size
::from_bits(16)).map(|v
| i16::try_from(v
).unwrap())
312 /// Tries to convert the `ScalarInt` to i32.
313 /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }`
314 /// and returns the `ScalarInt`s size in that case.
315 pub fn try_to_i32(self) -> Result
<i32, Size
> {
316 self.try_to_int(Size
::from_bits(32)).map(|v
| i32::try_from(v
).unwrap())
319 /// Tries to convert the `ScalarInt` to i64.
320 /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }`
321 /// and returns the `ScalarInt`s size in that case.
322 pub fn try_to_i64(self) -> Result
<i64, Size
> {
323 self.try_to_int(Size
::from_bits(64)).map(|v
| i64::try_from(v
).unwrap())
326 /// Tries to convert the `ScalarInt` to i128.
327 /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }`
328 /// and returns the `ScalarInt`s size in that case.
329 pub fn try_to_i128(self) -> Result
<i128
, Size
> {
330 self.try_to_int(Size
::from_bits(128)).map(|v
| i128
::try_from(v
).unwrap())
337 impl From
<$ty
> for ScalarInt
{
339 fn from(u
: $ty
) -> Self {
342 size
: std
::mem
::size_of
::<$ty
>() as u8,
350 macro_rules
! try_from
{
353 impl TryFrom
<ScalarInt
> for $ty
{
356 fn try_from(int
: ScalarInt
) -> Result
<Self, Size
> {
357 // The `unwrap` cannot fail because to_bits (if it succeeds)
358 // is guaranteed to return a value that fits into the size.
359 int
.to_bits(Size
::from_bytes(std
::mem
::size_of
::<$ty
>()))
360 .map(|u
| u
.try_into().unwrap())
367 from
!(u8, u16, u32, u64, u128
, bool
);
368 try_from
!(u8, u16, u32, u64, u128
);
370 impl TryFrom
<ScalarInt
> for bool
{
373 fn try_from(int
: ScalarInt
) -> Result
<Self, Size
> {
374 int
.to_bits(Size
::from_bytes(1)).and_then(|u
| match u
{
377 _
=> Err(Size
::from_bytes(1)),
382 impl From
<char> for ScalarInt
{
384 fn from(c
: char) -> Self {
385 Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
389 /// Error returned when a conversion from ScalarInt to char fails.
391 pub struct CharTryFromScalarInt
;
393 impl TryFrom
<ScalarInt
> for char {
394 type Error
= CharTryFromScalarInt
;
397 fn try_from(int
: ScalarInt
) -> Result
<Self, Self::Error
> {
398 let Ok(bits
) = int
.to_bits(Size
::from_bytes(std
::mem
::size_of
::<char>())) else {
399 return Err(CharTryFromScalarInt
);
401 match char::from_u32(bits
.try_into().unwrap()) {
403 None
=> Err(CharTryFromScalarInt
),
408 impl From
<Single
> for ScalarInt
{
410 fn from(f
: Single
) -> Self {
411 // We trust apfloat to give us properly truncated data.
412 Self { data: f.to_bits(), size: 4 }
416 impl TryFrom
<ScalarInt
> for Single
{
419 fn try_from(int
: ScalarInt
) -> Result
<Self, Size
> {
420 int
.to_bits(Size
::from_bytes(4)).map(Self::from_bits
)
424 impl From
<Double
> for ScalarInt
{
426 fn from(f
: Double
) -> Self {
427 // We trust apfloat to give us properly truncated data.
428 Self { data: f.to_bits(), size: 8 }
432 impl TryFrom
<ScalarInt
> for Double
{
435 fn try_from(int
: ScalarInt
) -> Result
<Self, Size
> {
436 int
.to_bits(Size
::from_bytes(8)).map(Self::from_bits
)
440 impl fmt
::Debug
for ScalarInt
{
441 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
446 // Dispatch to LowerHex below.
447 write
!(f
, "0x{:x}", self)
452 impl fmt
::LowerHex
for ScalarInt
{
453 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
455 // Format as hex number wide enough to fit any value of the given `size`.
456 // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
457 // Using a block `{self.data}` here to force a copy instead of using `self.data`
458 // directly, because `write!` takes references to its formatting arguments and
459 // would thus borrow `self.data`. Since `Self`
460 // is a packed struct, that would create a possibly unaligned reference, which
462 write
!(f
, "{:01$x}", { self.data }
, self.size
as usize * 2)
466 impl fmt
::UpperHex
for ScalarInt
{
467 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
469 // Format as hex number wide enough to fit any value of the given `size`.
470 // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
471 // Using a block `{self.data}` here to force a copy instead of using `self.data`
472 // directly, because `write!` takes references to its formatting arguments and
473 // would thus borrow `self.data`. Since `Self`
474 // is a packed struct, that would create a possibly unaligned reference, which
476 write
!(f
, "{:01$X}", { self.data }
, self.size
as usize * 2)
480 impl fmt
::Display
for ScalarInt
{
481 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
483 write
!(f
, "{}", { self.data }
)