1
1
use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
2
2
use rustc_middle:: ty:: { self , AdtDef , IntTy , Ty , TyCtxt , UintTy , VariantDiscr } ;
3
+ use rustc_span:: def_id:: DefId ;
3
4
use rustc_target:: abi:: Size ;
4
5
5
6
/// 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 {
26
27
}
27
28
}
28
29
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
+
29
79
pub ( super ) fn enum_ty_to_nbits ( adt : & AdtDef , tcx : TyCtxt < ' _ > ) -> u64 {
30
80
let mut explicit = 0i128 ;
31
81
let ( start, end) = adt
32
82
. variants
33
83
. iter ( )
34
- . fold ( ( i128 :: MAX , i128:: MIN ) , |( start, end) , variant| match variant. discr {
84
+ . fold ( ( 0 , i128:: MIN ) , |( start, end) , variant| match variant. discr {
35
85
VariantDiscr :: Relative ( x) => match explicit. checked_add ( i128:: from ( x) ) {
36
86
Some ( x) => ( start, end. max ( x) ) ,
37
87
None => ( i128:: MIN , end) ,
38
88
} ,
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) ,
67
102
} ,
68
103
} ) ;
69
104
70
- if start >= end {
105
+ if start > end {
106
+ // No variants.
71
107
0
72
108
} else {
73
109
let neg_bits = if start < 0 {
0 commit comments