• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use rustc_apfloat::ieee::{Double, Single};
2 use rustc_apfloat::Float;
3 use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
4 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
5 use rustc_target::abi::Size;
6 use std::fmt;
7 use std::num::NonZeroU8;
8 
9 use crate::ty::TyCtxt;
10 
11 #[derive(Copy, Clone)]
12 /// A type for representing any integer. Only used for printing.
13 pub struct ConstInt {
14     /// The "untyped" variant of `ConstInt`.
15     int: ScalarInt,
16     /// Whether the value is of a signed integer type.
17     signed: bool,
18     /// Whether the value is a `usize` or `isize` type.
19     is_ptr_sized_integral: bool,
20 }
21 
22 impl ConstInt {
new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self23     pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
24         Self { int, signed, is_ptr_sized_integral }
25     }
26 }
27 
28 impl std::fmt::Debug for ConstInt {
fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result29     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30         let Self { int, signed, is_ptr_sized_integral } = *self;
31         let size = int.size().bytes();
32         let raw = int.data;
33         if signed {
34             let bit_size = size * 8;
35             let min = 1u128 << (bit_size - 1);
36             let max = min - 1;
37             if raw == min {
38                 match (size, is_ptr_sized_integral) {
39                     (_, true) => write!(fmt, "isize::MIN"),
40                     (1, _) => write!(fmt, "i8::MIN"),
41                     (2, _) => write!(fmt, "i16::MIN"),
42                     (4, _) => write!(fmt, "i32::MIN"),
43                     (8, _) => write!(fmt, "i64::MIN"),
44                     (16, _) => write!(fmt, "i128::MIN"),
45                     _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
46                 }
47             } else if raw == max {
48                 match (size, is_ptr_sized_integral) {
49                     (_, true) => write!(fmt, "isize::MAX"),
50                     (1, _) => write!(fmt, "i8::MAX"),
51                     (2, _) => write!(fmt, "i16::MAX"),
52                     (4, _) => write!(fmt, "i32::MAX"),
53                     (8, _) => write!(fmt, "i64::MAX"),
54                     (16, _) => write!(fmt, "i128::MAX"),
55                     _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
56                 }
57             } else {
58                 match size {
59                     1 => write!(fmt, "{}", raw as i8)?,
60                     2 => write!(fmt, "{}", raw as i16)?,
61                     4 => write!(fmt, "{}", raw as i32)?,
62                     8 => write!(fmt, "{}", raw as i64)?,
63                     16 => write!(fmt, "{}", raw as i128)?,
64                     _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
65                 }
66                 if fmt.alternate() {
67                     match (size, is_ptr_sized_integral) {
68                         (_, true) => write!(fmt, "_isize")?,
69                         (1, _) => write!(fmt, "_i8")?,
70                         (2, _) => write!(fmt, "_i16")?,
71                         (4, _) => write!(fmt, "_i32")?,
72                         (8, _) => write!(fmt, "_i64")?,
73                         (16, _) => write!(fmt, "_i128")?,
74                         _ => bug!(),
75                     }
76                 }
77                 Ok(())
78             }
79         } else {
80             let max = Size::from_bytes(size).truncate(u128::MAX);
81             if raw == max {
82                 match (size, is_ptr_sized_integral) {
83                     (_, true) => write!(fmt, "usize::MAX"),
84                     (1, _) => write!(fmt, "u8::MAX"),
85                     (2, _) => write!(fmt, "u16::MAX"),
86                     (4, _) => write!(fmt, "u32::MAX"),
87                     (8, _) => write!(fmt, "u64::MAX"),
88                     (16, _) => write!(fmt, "u128::MAX"),
89                     _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
90                 }
91             } else {
92                 match size {
93                     1 => write!(fmt, "{}", raw as u8)?,
94                     2 => write!(fmt, "{}", raw as u16)?,
95                     4 => write!(fmt, "{}", raw as u32)?,
96                     8 => write!(fmt, "{}", raw as u64)?,
97                     16 => write!(fmt, "{}", raw as u128)?,
98                     _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
99                 }
100                 if fmt.alternate() {
101                     match (size, is_ptr_sized_integral) {
102                         (_, true) => write!(fmt, "_usize")?,
103                         (1, _) => write!(fmt, "_u8")?,
104                         (2, _) => write!(fmt, "_u16")?,
105                         (4, _) => write!(fmt, "_u32")?,
106                         (8, _) => write!(fmt, "_u64")?,
107                         (16, _) => write!(fmt, "_u128")?,
108                         _ => bug!(),
109                     }
110                 }
111                 Ok(())
112             }
113         }
114     }
115 }
116 
117 impl IntoDiagnosticArg for ConstInt {
118     // FIXME this simply uses the Debug impl, but we could probably do better by converting both
119     // to an inherent method that returns `Cow`.
into_diagnostic_arg(self) -> DiagnosticArgValue<'static>120     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
121         DiagnosticArgValue::Str(format!("{self:?}").into())
122     }
123 }
124 
125 /// The raw bytes of a simple value.
126 ///
127 /// This is a packed struct in order to allow this type to be optimally embedded in enums
128 /// (like Scalar).
129 #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
130 #[repr(packed)]
131 pub struct ScalarInt {
132     /// The first `size` bytes of `data` are the value.
133     /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
134     data: u128,
135     size: NonZeroU8,
136 }
137 
138 // Cannot derive these, as the derives take references to the fields, and we
139 // can't take references to fields of packed structs.
140 impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher)141     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
142         // Using a block `{self.data}` here to force a copy instead of using `self.data`
143         // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
144         // Since `Self` is a packed struct, that would create a possibly unaligned reference,
145         // which is UB.
146         { self.data }.hash_stable(hcx, hasher);
147         self.size.get().hash_stable(hcx, hasher);
148     }
149 }
150 
151 impl<S: Encoder> Encodable<S> for ScalarInt {
encode(&self, s: &mut S)152     fn encode(&self, s: &mut S) {
153         let size = self.size.get();
154         s.emit_u8(size);
155         s.emit_raw_bytes(&self.data.to_le_bytes()[..size as usize]);
156     }
157 }
158 
159 impl<D: Decoder> Decodable<D> for ScalarInt {
decode(d: &mut D) -> ScalarInt160     fn decode(d: &mut D) -> ScalarInt {
161         let mut data = [0u8; 16];
162         let size = d.read_u8();
163         data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
164         ScalarInt { data: u128::from_le_bytes(data), size: NonZeroU8::new(size).unwrap() }
165     }
166 }
167 
168 impl ScalarInt {
169     pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() };
170 
171     pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() };
172 
173     #[inline]
size(self) -> Size174     pub fn size(self) -> Size {
175         Size::from_bytes(self.size.get())
176     }
177 
178     /// Make sure the `data` fits in `size`.
179     /// This is guaranteed by all constructors here, but having had this check saved us from
180     /// bugs many times in the past, so keeping it around is definitely worth it.
181     #[inline(always)]
check_data(self)182     fn check_data(self) {
183         // Using a block `{self.data}` here to force a copy instead of using `self.data`
184         // directly, because `debug_assert_eq` takes references to its arguments and formatting
185         // arguments and would thus borrow `self.data`. Since `Self`
186         // is a packed struct, that would create a possibly unaligned reference, which
187         // is UB.
188         debug_assert_eq!(
189             self.size().truncate(self.data),
190             { self.data },
191             "Scalar value {:#x} exceeds size of {} bytes",
192             { self.data },
193             self.size
194         );
195     }
196 
197     #[inline]
null(size: Size) -> Self198     pub fn null(size: Size) -> Self {
199         Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() }
200     }
201 
202     #[inline]
is_null(self) -> bool203     pub fn is_null(self) -> bool {
204         self.data == 0
205     }
206 
207     #[inline]
try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self>208     pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
209         let data = i.into();
210         if size.truncate(data) == data {
211             Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
212         } else {
213             None
214         }
215     }
216 
217     #[inline]
try_from_int(i: impl Into<i128>, size: Size) -> Option<Self>218     pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
219         let i = i.into();
220         // `into` performed sign extension, we have to truncate
221         let truncated = size.truncate(i as u128);
222         if size.sign_extend(truncated) as i128 == i {
223             Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
224         } else {
225             None
226         }
227     }
228 
229     #[inline]
assert_bits(self, target_size: Size) -> u128230     pub fn assert_bits(self, target_size: Size) -> u128 {
231         self.to_bits(target_size).unwrap_or_else(|size| {
232             bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
233         })
234     }
235 
236     #[inline]
to_bits(self, target_size: Size) -> Result<u128, Size>237     pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
238         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
239         if target_size.bytes() == u64::from(self.size.get()) {
240             self.check_data();
241             Ok(self.data)
242         } else {
243             Err(self.size())
244         }
245     }
246 
247     #[inline]
try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size>248     pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
249         Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
250     }
251 
252     /// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
253     /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
254     /// `ScalarInt`s size in that case.
255     #[inline]
try_to_uint(self, size: Size) -> Result<u128, Size>256     pub fn try_to_uint(self, size: Size) -> Result<u128, Size> {
257         self.to_bits(size)
258     }
259 
260     // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt`
261     // in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size`
262     // value of the `ScalarInt` in that case.
263     #[inline]
try_to_bool(self) -> Result<bool, Size>264     pub fn try_to_bool(self) -> Result<bool, Size> {
265         match self.try_to_u8()? {
266             0 => Ok(false),
267             1 => Ok(true),
268             _ => Err(self.size()),
269         }
270     }
271 
272     // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
273     // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
274     // that case.
275     #[inline]
try_to_u8(self) -> Result<u8, Size>276     pub fn try_to_u8(self) -> Result<u8, Size> {
277         self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
278     }
279 
280     /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
281     /// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
282     /// that case.
283     #[inline]
try_to_u16(self) -> Result<u16, Size>284     pub fn try_to_u16(self) -> Result<u16, Size> {
285         self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
286     }
287 
288     /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
289     /// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
290     /// that case.
291     #[inline]
try_to_u32(self) -> Result<u32, Size>292     pub fn try_to_u32(self) -> Result<u32, Size> {
293         self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
294     }
295 
296     /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
297     /// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
298     /// that case.
299     #[inline]
try_to_u64(self) -> Result<u64, Size>300     pub fn try_to_u64(self) -> Result<u64, Size> {
301         self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
302     }
303 
304     /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
305     /// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
306     /// that case.
307     #[inline]
try_to_u128(self) -> Result<u128, Size>308     pub fn try_to_u128(self) -> Result<u128, Size> {
309         self.to_bits(Size::from_bits(128))
310     }
311 
312     /// Tries to convert the `ScalarInt` to a signed integer of the given size.
313     /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
314     /// `ScalarInt`s size in that case.
315     #[inline]
try_to_int(self, size: Size) -> Result<i128, Size>316     pub fn try_to_int(self, size: Size) -> Result<i128, Size> {
317         let b = self.to_bits(size)?;
318         Ok(size.sign_extend(b) as i128)
319     }
320 
321     /// Tries to convert the `ScalarInt` to i8.
322     /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 1 }`
323     /// and returns the `ScalarInt`s size in that case.
try_to_i8(self) -> Result<i8, Size>324     pub fn try_to_i8(self) -> Result<i8, Size> {
325         self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
326     }
327 
328     /// Tries to convert the `ScalarInt` to i16.
329     /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 2 }`
330     /// and returns the `ScalarInt`s size in that case.
try_to_i16(self) -> Result<i16, Size>331     pub fn try_to_i16(self) -> Result<i16, Size> {
332         self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
333     }
334 
335     /// Tries to convert the `ScalarInt` to i32.
336     /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 4 }`
337     /// and returns the `ScalarInt`s size in that case.
try_to_i32(self) -> Result<i32, Size>338     pub fn try_to_i32(self) -> Result<i32, Size> {
339         self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
340     }
341 
342     /// Tries to convert the `ScalarInt` to i64.
343     /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 8 }`
344     /// and returns the `ScalarInt`s size in that case.
try_to_i64(self) -> Result<i64, Size>345     pub fn try_to_i64(self) -> Result<i64, Size> {
346         self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
347     }
348 
349     /// Tries to convert the `ScalarInt` to i128.
350     /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }`
351     /// and returns the `ScalarInt`s size in that case.
try_to_i128(self) -> Result<i128, Size>352     pub fn try_to_i128(self) -> Result<i128, Size> {
353         self.try_to_int(Size::from_bits(128))
354     }
355 }
356 
357 macro_rules! from {
358     ($($ty:ty),*) => {
359         $(
360             impl From<$ty> for ScalarInt {
361                 #[inline]
362                 fn from(u: $ty) -> Self {
363                     Self {
364                         data: u128::from(u),
365                         size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(),
366                     }
367                 }
368             }
369         )*
370     }
371 }
372 
373 macro_rules! try_from {
374     ($($ty:ty),*) => {
375         $(
376             impl TryFrom<ScalarInt> for $ty {
377                 type Error = Size;
378                 #[inline]
379                 fn try_from(int: ScalarInt) -> Result<Self, Size> {
380                     // The `unwrap` cannot fail because to_bits (if it succeeds)
381                     // is guaranteed to return a value that fits into the size.
382                     int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>()))
383                        .map(|u| u.try_into().unwrap())
384                 }
385             }
386         )*
387     }
388 }
389 
390 from!(u8, u16, u32, u64, u128, bool);
391 try_from!(u8, u16, u32, u64, u128);
392 
393 impl TryFrom<ScalarInt> for bool {
394     type Error = Size;
395     #[inline]
try_from(int: ScalarInt) -> Result<Self, Size>396     fn try_from(int: ScalarInt) -> Result<Self, Size> {
397         int.to_bits(Size::from_bytes(1)).and_then(|u| match u {
398             0 => Ok(false),
399             1 => Ok(true),
400             _ => Err(Size::from_bytes(1)),
401         })
402     }
403 }
404 
405 impl From<char> for ScalarInt {
406     #[inline]
from(c: char) -> Self407     fn from(c: char) -> Self {
408         Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() }
409     }
410 }
411 
412 /// Error returned when a conversion from ScalarInt to char fails.
413 #[derive(Debug)]
414 pub struct CharTryFromScalarInt;
415 
416 impl TryFrom<ScalarInt> for char {
417     type Error = CharTryFromScalarInt;
418 
419     #[inline]
try_from(int: ScalarInt) -> Result<Self, Self::Error>420     fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
421         let Ok(bits) = int.to_bits(Size::from_bytes(std::mem::size_of::<char>())) else  {
422             return Err(CharTryFromScalarInt);
423         };
424         match char::from_u32(bits.try_into().unwrap()) {
425             Some(c) => Ok(c),
426             None => Err(CharTryFromScalarInt),
427         }
428     }
429 }
430 
431 impl From<Single> for ScalarInt {
432     #[inline]
from(f: Single) -> Self433     fn from(f: Single) -> Self {
434         // We trust apfloat to give us properly truncated data.
435         Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() }
436     }
437 }
438 
439 impl TryFrom<ScalarInt> for Single {
440     type Error = Size;
441     #[inline]
try_from(int: ScalarInt) -> Result<Self, Size>442     fn try_from(int: ScalarInt) -> Result<Self, Size> {
443         int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
444     }
445 }
446 
447 impl From<Double> for ScalarInt {
448     #[inline]
from(f: Double) -> Self449     fn from(f: Double) -> Self {
450         // We trust apfloat to give us properly truncated data.
451         Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() }
452     }
453 }
454 
455 impl TryFrom<ScalarInt> for Double {
456     type Error = Size;
457     #[inline]
try_from(int: ScalarInt) -> Result<Self, Size>458     fn try_from(int: ScalarInt) -> Result<Self, Size> {
459         int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
460     }
461 }
462 
463 impl fmt::Debug for ScalarInt {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result464     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465         // Dispatch to LowerHex below.
466         write!(f, "0x{:x}", self)
467     }
468 }
469 
470 impl fmt::LowerHex for ScalarInt {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result471     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472         self.check_data();
473         if f.alternate() {
474             // Like regular ints, alternate flag adds leading `0x`.
475             write!(f, "0x")?;
476         }
477         // Format as hex number wide enough to fit any value of the given `size`.
478         // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
479         // Using a block `{self.data}` here to force a copy instead of using `self.data`
480         // directly, because `write!` takes references to its formatting arguments and
481         // would thus borrow `self.data`. Since `Self`
482         // is a packed struct, that would create a possibly unaligned reference, which
483         // is UB.
484         write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
485     }
486 }
487 
488 impl fmt::UpperHex for ScalarInt {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result489     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490         self.check_data();
491         // Format as hex number wide enough to fit any value of the given `size`.
492         // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
493         // Using a block `{self.data}` here to force a copy instead of using `self.data`
494         // directly, because `write!` takes references to its formatting arguments and
495         // would thus borrow `self.data`. Since `Self`
496         // is a packed struct, that would create a possibly unaligned reference, which
497         // is UB.
498         write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
499     }
500 }
501 
502 impl fmt::Display for ScalarInt {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result503     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504         self.check_data();
505         write!(f, "{}", { self.data })
506     }
507 }
508