@@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId;
1010use rustc_hir:: { Expr , TyKind , Unsafety } ;
1111use rustc_infer:: infer:: TyCtxtInferExt ;
1212use rustc_lint:: LateContext ;
13+ use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
1314use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
1415use 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 ,
1617} ;
1718use rustc_span:: symbol:: Ident ;
1819use rustc_span:: { sym, Span , Symbol , DUMMY_SP } ;
20+ use rustc_target:: abi:: { Size , VariantIdx } ;
1921use rustc_trait_selection:: infer:: InferCtxtExt ;
2022use rustc_trait_selection:: traits:: query:: normalize:: AtExt ;
2123use std:: iter;
@@ -515,3 +517,58 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
515517 }
516518 }
517519}
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