@@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId;
10
10
use rustc_hir:: { Expr , TyKind , Unsafety } ;
11
11
use rustc_infer:: infer:: TyCtxtInferExt ;
12
12
use rustc_lint:: LateContext ;
13
+ use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
13
14
use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
14
15
use rustc_middle:: ty:: {
15
- self , AdtDef , Binder , FnSig , IntTy , Predicate , PredicateKind , Ty , TyCtxt , TypeFoldable , UintTy ,
16
+ self , AdtDef , Binder , FnSig , IntTy , Predicate , PredicateKind , Ty , TyCtxt , TypeFoldable , UintTy , VariantDiscr ,
16
17
} ;
17
18
use rustc_span:: symbol:: Ident ;
18
19
use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
20
+ use rustc_target:: abi:: { Size , VariantIdx } ;
19
21
use rustc_trait_selection:: infer:: InferCtxtExt ;
20
22
use rustc_trait_selection:: traits:: query:: normalize:: AtExt ;
21
23
use std:: iter;
@@ -515,3 +517,58 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
515
517
}
516
518
}
517
519
}
520
+
521
+ #[ derive( Clone , Copy ) ]
522
+ pub enum EnumValue {
523
+ Unsigned ( u128 ) ,
524
+ Signed ( i128 ) ,
525
+ }
526
+ impl core:: ops:: Add < u32 > for EnumValue {
527
+ type Output = Self ;
528
+ fn add ( self , n : u32 ) -> Self :: Output {
529
+ match self {
530
+ Self :: Unsigned ( x) => Self :: Unsigned ( x + u128:: from ( n) ) ,
531
+ Self :: Signed ( x) => Self :: Signed ( x + i128:: from ( n) ) ,
532
+ }
533
+ }
534
+ }
535
+
536
+ /// Attempts to read the given constant as though it were an an enum value.
537
+ #[ allow( clippy:: cast_possible_truncation, clippy:: cast_possible_wrap) ]
538
+ pub fn read_explicit_enum_value ( tcx : TyCtxt < ' _ > , id : DefId ) -> Option < EnumValue > {
539
+ if let Ok ( ConstValue :: Scalar ( Scalar :: Int ( value) ) ) = tcx. const_eval_poly ( id) {
540
+ match tcx. type_of ( id) . kind ( ) {
541
+ ty:: Int ( _) => Some ( EnumValue :: Signed ( match value. size ( ) . bytes ( ) {
542
+ 1 => i128:: from ( value. assert_bits ( Size :: from_bytes ( 1 ) ) as u8 as i8 ) ,
543
+ 2 => i128:: from ( value. assert_bits ( Size :: from_bytes ( 2 ) ) as u16 as i16 ) ,
544
+ 4 => i128:: from ( value. assert_bits ( Size :: from_bytes ( 4 ) ) as u32 as i32 ) ,
545
+ 8 => i128:: from ( value. assert_bits ( Size :: from_bytes ( 8 ) ) as u64 as i64 ) ,
546
+ 16 => value. assert_bits ( Size :: from_bytes ( 16 ) ) as i128 ,
547
+ _ => return None ,
548
+ } ) ) ,
549
+ ty:: Uint ( _) => Some ( EnumValue :: Unsigned ( match value. size ( ) . bytes ( ) {
550
+ 1 => value. assert_bits ( Size :: from_bytes ( 1 ) ) ,
551
+ 2 => value. assert_bits ( Size :: from_bytes ( 2 ) ) ,
552
+ 4 => value. assert_bits ( Size :: from_bytes ( 4 ) ) ,
553
+ 8 => value. assert_bits ( Size :: from_bytes ( 8 ) ) ,
554
+ 16 => value. assert_bits ( Size :: from_bytes ( 16 ) ) ,
555
+ _ => return None ,
556
+ } ) ) ,
557
+ _ => None ,
558
+ }
559
+ } else {
560
+ None
561
+ }
562
+ }
563
+
564
+ /// Gets the value of the given variant.
565
+ pub fn get_discriminant_value ( tcx : TyCtxt < ' _ > , adt : & ' _ AdtDef , i : VariantIdx ) -> EnumValue {
566
+ let variant = & adt. variants [ i] ;
567
+ match variant. discr {
568
+ VariantDiscr :: Explicit ( id) => read_explicit_enum_value ( tcx, id) . unwrap ( ) ,
569
+ VariantDiscr :: Relative ( x) => match adt. variants [ ( i. as_usize ( ) - x as usize ) . into ( ) ] . discr {
570
+ VariantDiscr :: Explicit ( id) => read_explicit_enum_value ( tcx, id) . unwrap ( ) + x,
571
+ VariantDiscr :: Relative ( _) => EnumValue :: Unsigned ( x. into ( ) ) ,
572
+ } ,
573
+ }
574
+ }
0 commit comments