11use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
22use rustc_middle:: ty:: { self , AdtDef , IntTy , Ty , TyCtxt , UintTy , VariantDiscr } ;
3+ use rustc_span:: def_id:: DefId ;
34use rustc_target:: abi:: Size ;
45
56/// Returns the size in bits of an integral type.
@@ -26,48 +27,83 @@ pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
2627 }
2728}
2829
30+ pub ( super ) enum EnumValue {
31+ Unsigned ( u128 ) ,
32+ Signed ( i128 ) ,
33+ }
34+ impl EnumValue {
35+ pub ( super ) fn add ( self , n : u32 ) -> Self {
36+ match self {
37+ Self :: Unsigned ( x) => Self :: Unsigned ( x + u128:: from ( n) ) ,
38+ Self :: Signed ( x) => Self :: Signed ( x + i128:: from ( n) ) ,
39+ }
40+ }
41+
42+ pub ( super ) fn nbits ( self ) -> u64 {
43+ match self {
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 ( ) ,
47+ }
48+ . into ( )
49+ }
50+ }
51+
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 ,
62+ _ => return None ,
63+ } ) ) ,
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 ) ) ,
70+ _ => return None ,
71+ } ) ) ,
72+ _ => None ,
73+ }
74+ } else {
75+ None
76+ }
77+ }
78+
2979pub ( super ) fn enum_ty_to_nbits ( adt : & AdtDef , tcx : TyCtxt < ' _ > ) -> u64 {
3080 let mut explicit = 0i128 ;
3181 let ( start, end) = adt
3282 . variants
3383 . iter ( )
34- . fold ( ( i128 :: MAX , i128:: MIN ) , |( start, end) , variant| match variant. discr {
84+ . fold ( ( 0 , i128:: MIN ) , |( start, end) , variant| match variant. discr {
3585 VariantDiscr :: Relative ( x) => match explicit. checked_add ( i128:: from ( x) ) {
3686 Some ( x) => ( start, end. max ( x) ) ,
3787 None => ( i128:: MIN , end) ,
3888 } ,
39- VariantDiscr :: Explicit ( id) => {
40- let ty = tcx. type_of ( id) ;
41- if let Ok ( ConstValue :: Scalar ( Scalar :: Int ( value) ) ) = tcx. const_eval_poly ( id) {
42- #[ allow( clippy:: cast_possible_truncation, clippy:: cast_possible_wrap) ]
43- let value = match ( value. size ( ) . bytes ( ) , ty. kind ( ) ) {
44- ( 1 , ty:: Int ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 1 ) ) as u8 as i8 ) ,
45- ( 1 , ty:: Uint ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 1 ) ) as u8 ) ,
46- ( 2 , ty:: Int ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 2 ) ) as u16 as i16 ) ,
47- ( 2 , ty:: Uint ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 2 ) ) as u16 ) ,
48- ( 4 , ty:: Int ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 4 ) ) as u32 as i32 ) ,
49- ( 4 , ty:: Uint ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 4 ) ) as u32 ) ,
50- ( 8 , ty:: Int ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 8 ) ) as u64 as i64 ) ,
51- ( 8 , ty:: Uint ( _) ) => i128:: from ( value. assert_bits ( Size :: from_bytes ( 8 ) ) as u64 ) ,
52- ( 16 , ty:: Int ( _) ) => value. assert_bits ( Size :: from_bytes ( 16 ) ) as i128 ,
53- ( 16 , ty:: Uint ( _) ) => match i128:: try_from ( value. assert_bits ( Size :: from_bytes ( 16 ) ) ) {
54- Ok ( x) => x,
55- // Requires 128 bits
56- Err ( _) => return ( i128:: MIN , end) ,
57- } ,
58- // Shouldn't happen if compilation was successful
59- _ => return ( start, end) ,
60- } ;
61- explicit = value;
62- ( start. min ( value) , end. max ( value) )
63- } else {
64- // Shouldn't happen if compilation was successful
65- ( start, end)
66- }
89+ VariantDiscr :: Explicit ( id) => match read_explicit_enum_value ( tcx, id) {
90+ Some ( EnumValue :: Signed ( x) ) => {
91+ explicit = x;
92+ ( start. min ( x) , end. max ( x) )
93+ } ,
94+ Some ( EnumValue :: Unsigned ( x) ) => match i128:: try_from ( x) {
95+ Ok ( x) => {
96+ explicit = x;
97+ ( start, end. max ( x) )
98+ } ,
99+ Err ( _) => ( i128:: MIN , end) ,
100+ } ,
101+ None => ( start, end) ,
67102 } ,
68103 } ) ;
69104
70- if start >= end {
105+ if start > end {
106+ // No variants.
71107 0
72108 } else {
73109 let neg_bits = if start < 0 {
0 commit comments