1 use rustc_middle::mir::interpret::{ConstValue, Scalar};
2 use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
3 use rustc_span::def_id::DefId;
4 use rustc_target::abi::Size;
6 /// Returns the size in bits of an integral type.
7 /// Will return 0 if the type is not an int or uint variant
8 pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
10 ty::Int(i) => match i {
11 IntTy::Isize => tcx.data_layout.pointer_size.bits(),
18 ty::Uint(i) => match i {
19 UintTy::Usize => tcx.data_layout.pointer_size.bits(),
30 pub(super) enum EnumValue {
35 pub(super) fn add(self, n: u32) -> Self {
37 Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)),
38 Self::Signed(x) => Self::Signed(x + i128::from(n)),
42 pub(super) fn nbits(self) -> u64 {
44 Self::Unsigned(x) => 128 - x.leading_zeros(),
45 Self::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1,
46 Self::Signed(x) => 128 - x.leading_zeros(),
52 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
53 pub(super) fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
54 if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
55 match tcx.type_of(id).kind() {
56 ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
57 1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
58 2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
59 4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32),
60 8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64),
61 16 => value.assert_bits(Size::from_bytes(16)) as i128,
64 ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() {
65 1 => value.assert_bits(Size::from_bytes(1)),
66 2 => value.assert_bits(Size::from_bytes(2)),
67 4 => value.assert_bits(Size::from_bytes(4)),
68 8 => value.assert_bits(Size::from_bytes(8)),
69 16 => value.assert_bits(Size::from_bytes(16)),
79 pub(super) fn enum_ty_to_nbits(adt: &AdtDef, tcx: TyCtxt<'_>) -> u64 {
80 let mut explicit = 0i128;
81 let (start, end) = adt
84 .fold((0, i128::MIN), |(start, end), variant| match variant.discr {
85 VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) {
86 Some(x) => (start, end.max(x)),
87 None => (i128::MIN, end),
89 VariantDiscr::Explicit(id) => match read_explicit_enum_value(tcx, id) {
90 Some(EnumValue::Signed(x)) => {
92 (start.min(x), end.max(x))
94 Some(EnumValue::Unsigned(x)) => match i128::try_from(x) {
99 Err(_) => (i128::MIN, end),
101 None => (start, end),
109 let neg_bits = if start < 0 {
110 128 - (-(start + 1)).leading_zeros() + 1
114 let pos_bits = if end > 0 { 128 - end.leading_zeros() } else { 0 };
115 neg_bits.max(pos_bits).into()