]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_middle/src/ty/consts/int.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / consts / int.rs
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};
6 use std::fmt;
7
8 use crate::ty::TyCtxt;
9
10 #[derive(Copy, Clone)]
11 /// A type for representing any integer. Only used for printing.
12 pub struct ConstInt {
13 /// The "untyped" variant of `ConstInt`.
14 int: ScalarInt,
15 /// Whether the value is of a signed integer type.
16 signed: bool,
17 /// Whether the value is a `usize` or `isize` type.
18 is_ptr_sized_integral: bool,
19 }
20
21 impl ConstInt {
22 pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
23 Self { int, signed, is_ptr_sized_integral }
24 }
25 }
26
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();
31 let raw = int.data;
32 if signed {
33 let bit_size = size * 8;
34 let min = 1u128 << (bit_size - 1);
35 let max = min - 1;
36 if raw == min {
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),
45 }
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),
55 }
56 } else {
57 match size {
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),
64 }
65 if fmt.alternate() {
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")?,
73 _ => bug!(),
74 }
75 }
76 Ok(())
77 }
78 } else {
79 let max = Size::from_bytes(size).truncate(u128::MAX);
80 if raw == 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),
89 }
90 } else {
91 match size {
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),
98 }
99 if fmt.alternate() {
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")?,
107 _ => bug!(),
108 }
109 }
110 Ok(())
111 }
112 }
113 }
114 }
115
116 /// The raw bytes of a simple value.
117 ///
118 /// This is a packed struct in order to allow this type to be optimally embedded in enums
119 /// (like Scalar).
120 #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
121 #[repr(packed)]
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.
125 data: u128,
126 size: u8,
127 }
128
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,
136 // which is UB.
137 { self.data }.hash_stable(hcx, hasher);
138 self.size.hash_stable(hcx, hasher);
139 }
140 }
141
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);
146 }
147 }
148
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() }
152 }
153 }
154
155 impl ScalarInt {
156 pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };
157
158 pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };
159
160 pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };
161
162 #[inline]
163 pub fn size(self) -> Size {
164 Size::from_bytes(self.size)
165 }
166
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.
170 #[inline(always)]
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
176 // is UB.
177 debug_assert_eq!(
178 self.size().truncate(self.data),
179 { self.data },
180 "Scalar value {:#x} exceeds size of {} bytes",
181 { self.data },
182 self.size
183 );
184 }
185
186 #[inline]
187 pub fn null(size: Size) -> Self {
188 Self { data: 0, size: size.bytes() as u8 }
189 }
190
191 #[inline]
192 pub fn is_null(self) -> bool {
193 self.data == 0
194 }
195
196 #[inline]
197 pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
198 let data = i.into();
199 if size.truncate(data) == data {
200 Some(Self { data, size: size.bytes() as u8 })
201 } else {
202 None
203 }
204 }
205
206 #[inline]
207 pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
208 let i = i.into();
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 })
213 } else {
214 None
215 }
216 }
217
218 #[inline]
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())
222 })
223 }
224
225 #[inline]
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) {
229 self.check_data();
230 Ok(self.data)
231 } else {
232 Err(self.size())
233 }
234 }
235
236 #[inline]
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)
239 }
240
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.
244 #[inline]
245 pub fn try_to_uint(self, size: Size) -> Result<u128, Size> {
246 self.to_bits(size)
247 }
248
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
251 // that case.
252 #[inline]
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())
255 }
256
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
259 /// that case.
260 #[inline]
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())
263 }
264
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
267 /// that case.
268 #[inline]
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())
271 }
272
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
275 /// that case.
276 #[inline]
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())
279 }
280
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
283 /// that case.
284 #[inline]
285 pub fn try_to_u128(self) -> Result<u128, Size> {
286 self.to_bits(Size::from_bits(128))
287 }
288
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.
292 #[inline]
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)
296 }
297
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())
303 }
304
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())
310 }
311
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())
317 }
318
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())
324 }
325
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())
331 }
332 }
333
334 macro_rules! from {
335 ($($ty:ty),*) => {
336 $(
337 impl From<$ty> for ScalarInt {
338 #[inline]
339 fn from(u: $ty) -> Self {
340 Self {
341 data: u128::from(u),
342 size: std::mem::size_of::<$ty>() as u8,
343 }
344 }
345 }
346 )*
347 }
348 }
349
350 macro_rules! try_from {
351 ($($ty:ty),*) => {
352 $(
353 impl TryFrom<ScalarInt> for $ty {
354 type Error = Size;
355 #[inline]
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())
361 }
362 }
363 )*
364 }
365 }
366
367 from!(u8, u16, u32, u64, u128, bool);
368 try_from!(u8, u16, u32, u64, u128);
369
370 impl TryFrom<ScalarInt> for bool {
371 type Error = Size;
372 #[inline]
373 fn try_from(int: ScalarInt) -> Result<Self, Size> {
374 int.to_bits(Size::from_bytes(1)).and_then(|u| match u {
375 0 => Ok(false),
376 1 => Ok(true),
377 _ => Err(Size::from_bytes(1)),
378 })
379 }
380 }
381
382 impl From<char> for ScalarInt {
383 #[inline]
384 fn from(c: char) -> Self {
385 Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
386 }
387 }
388
389 /// Error returned when a conversion from ScalarInt to char fails.
390 #[derive(Debug)]
391 pub struct CharTryFromScalarInt;
392
393 impl TryFrom<ScalarInt> for char {
394 type Error = CharTryFromScalarInt;
395
396 #[inline]
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);
400 };
401 match char::from_u32(bits.try_into().unwrap()) {
402 Some(c) => Ok(c),
403 None => Err(CharTryFromScalarInt),
404 }
405 }
406 }
407
408 impl From<Single> for ScalarInt {
409 #[inline]
410 fn from(f: Single) -> Self {
411 // We trust apfloat to give us properly truncated data.
412 Self { data: f.to_bits(), size: 4 }
413 }
414 }
415
416 impl TryFrom<ScalarInt> for Single {
417 type Error = Size;
418 #[inline]
419 fn try_from(int: ScalarInt) -> Result<Self, Size> {
420 int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
421 }
422 }
423
424 impl From<Double> for ScalarInt {
425 #[inline]
426 fn from(f: Double) -> Self {
427 // We trust apfloat to give us properly truncated data.
428 Self { data: f.to_bits(), size: 8 }
429 }
430 }
431
432 impl TryFrom<ScalarInt> for Double {
433 type Error = Size;
434 #[inline]
435 fn try_from(int: ScalarInt) -> Result<Self, Size> {
436 int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
437 }
438 }
439
440 impl fmt::Debug for ScalarInt {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 if self.size == 0 {
443 self.check_data();
444 write!(f, "<ZST>")
445 } else {
446 // Dispatch to LowerHex below.
447 write!(f, "0x{:x}", self)
448 }
449 }
450 }
451
452 impl fmt::LowerHex for ScalarInt {
453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454 self.check_data();
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
461 // is UB.
462 write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
463 }
464 }
465
466 impl fmt::UpperHex for ScalarInt {
467 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468 self.check_data();
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
475 // is UB.
476 write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
477 }
478 }
479
480 impl fmt::Display for ScalarInt {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482 self.check_data();
483 write!(f, "{}", { self.data })
484 }
485 }