@@ -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
@@ -682,8 +687,31 @@ 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) ;
690+ // FIXME: WTF, some discriminants don't have integer type.
691+ use layout:: Primitive ;
692+ let discr_layout = self . layout_of ( match discr_layout. value {
693+ Primitive :: Int ( int, signed) => int. to_ty ( * self . tcx , signed) ,
694+ Primitive :: Pointer => self . tcx . types . usize ,
695+ Primitive :: Float ( ..) => bug ! ( "there are no float discriminants" ) ,
696+ } ) ?;
697+ let discr_val = ImmTy :: from_uint ( raw_discr, discr_layout) ;
698+ // We need to use machine arithmetic.
699+ let niche_start_val = ImmTy :: from_uint ( niche_start, discr_layout) ;
700+ let variants_start_val = ImmTy :: from_uint ( variants_start, discr_layout) ;
701+ let adjusted_discr = self . binary_op (
702+ mir:: BinOp :: Sub ,
703+ discr_val,
704+ niche_start_val,
705+ ) ?;
706+ let adjusted_discr = self . binary_op (
707+ mir:: BinOp :: Add ,
708+ adjusted_discr,
709+ variants_start_val,
710+ ) ?;
711+ let adjusted_discr = adjusted_discr
712+ . to_scalar ( ) ?
713+ . assert_bits ( discr_val. layout . size ) ;
714+ // Check if this is in the range that indicates an actual discriminant.
687715 if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
688716 let index = adjusted_discr as usize ;
689717 assert_eq ! ( index as u128 , adjusted_discr) ;
0 commit comments