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