11//! Functions concerning immediate values and operands, and reading from operands.
22//! All high-level functions to read from memory work on operands as sources.
33
4- use std:: convert:: TryInto ;
4+ use std:: convert:: { TryInto , TryFrom } ;
55
66use rustc:: { mir, ty} ;
77use rustc:: ty:: layout:: {
8- self , Size , LayoutOf , TyLayout , HasDataLayout , IntegerExt , VariantIdx ,
8+ self , Size , LayoutOf , TyLayout , HasDataLayout , IntegerExt , PrimitiveExt , VariantIdx ,
99} ;
1010
1111use rustc:: mir:: interpret:: {
@@ -609,15 +609,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
609609 ) -> InterpResult < ' tcx , ( u128 , VariantIdx ) > {
610610 trace ! ( "read_discriminant_value {:#?}" , rval. layout) ;
611611
612- let ( discr_kind, discr_index) = match rval. layout . variants {
612+ let ( discr_layout , discr_kind, discr_index) = match rval. layout . variants {
613613 layout:: Variants :: Single { index } => {
614614 let discr_val = rval. layout . ty . discriminant_for_variant ( * self . tcx , index) . map_or (
615615 index. as_u32 ( ) as u128 ,
616616 |discr| discr. val ) ;
617617 return Ok ( ( discr_val, index) ) ;
618618 }
619- layout:: Variants :: Multiple { ref discr_kind, discr_index, .. } =>
620- ( discr_kind, discr_index) ,
619+ layout:: Variants :: Multiple {
620+ discr : ref discr_layout,
621+ ref discr_kind,
622+ discr_index,
623+ ..
624+ } =>
625+ ( discr_layout, discr_kind, discr_index) ,
621626 } ;
622627
623628 // read raw discriminant value
@@ -634,7 +639,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
634639 . map_err ( |_| err_unsup ! ( InvalidDiscriminant ( raw_discr. erase_tag( ) ) ) ) ?;
635640 let real_discr = if discr_val. layout . ty . is_signed ( ) {
636641 // going from layout tag type to typeck discriminant type
637- // requires first sign extending with the layout discriminant
642+ // requires first sign extending with the discriminant layout
638643 let sexted = sign_extend ( bits_discr, discr_val. layout . size ) as i128 ;
639644 // and then zeroing with the typeck discriminant type
640645 let discr_ty = rval. layout . ty
@@ -666,8 +671,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
666671 ref niche_variants,
667672 niche_start,
668673 } => {
669- let variants_start = niche_variants. start ( ) . as_u32 ( ) as u128 ;
670- let variants_end = niche_variants. end ( ) . as_u32 ( ) as u128 ;
674+ let variants_start = niche_variants. start ( ) . as_u32 ( ) ;
675+ let variants_end = niche_variants. end ( ) . as_u32 ( ) ;
671676 let raw_discr = raw_discr. not_undef ( ) . map_err ( |_| {
672677 err_unsup ! ( InvalidDiscriminant ( ScalarMaybeUndef :: Undef ) )
673678 } ) ?;
@@ -682,18 +687,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
682687 ( dataful_variant. as_u32 ( ) as u128 , dataful_variant)
683688 } ,
684689 Ok ( raw_discr) => {
685- let adjusted_discr = raw_discr. wrapping_sub ( niche_start)
686- . wrapping_add ( variants_start) ;
687- if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
688- let index = adjusted_discr as usize ;
689- assert_eq ! ( index as u128 , adjusted_discr) ;
690- assert ! ( index < rval. layout. ty
690+ // We need to use machine arithmetic to get the relative variant idx:
691+ // variant_index_relative = discr_val - niche_start_val
692+ let discr_layout = self . layout_of ( discr_layout. value . to_int_ty ( * self . tcx ) ) ?;
693+ let discr_val = ImmTy :: from_uint ( raw_discr, discr_layout) ;
694+ let niche_start_val = ImmTy :: from_uint ( niche_start, discr_layout) ;
695+ let variant_index_relative_val = self . binary_op (
696+ mir:: BinOp :: Sub ,
697+ discr_val,
698+ niche_start_val,
699+ ) ?;
700+ let variant_index_relative = variant_index_relative_val
701+ . to_scalar ( ) ?
702+ . assert_bits ( discr_val. layout . size ) ;
703+ // Check if this is in the range that indicates an actual discriminant.
704+ if variant_index_relative <= u128:: from ( variants_end - variants_start) {
705+ let variant_index_relative = u32:: try_from ( variant_index_relative)
706+ . expect ( "we checked that this fits into a u32" ) ;
707+ // Then computing the absolute variant idx should not overflow any more.
708+ let variant_index = variants_start
709+ . checked_add ( variant_index_relative)
710+ . expect ( "oveflow computing absolute variant idx" ) ;
711+ assert ! ( ( variant_index as usize ) < rval. layout. ty
691712 . ty_adt_def( )
692713 . expect( "tagged layout for non adt" )
693714 . variants. len( ) ) ;
694- ( adjusted_discr , VariantIdx :: from_usize ( index ) )
715+ ( u128 :: from ( variant_index ) , VariantIdx :: from_u32 ( variant_index ) )
695716 } else {
696- ( dataful_variant. as_u32 ( ) as u128 , dataful_variant)
717+ ( u128 :: from ( dataful_variant. as_u32 ( ) ) , dataful_variant)
697718 }
698719 } ,
699720 }
0 commit comments