@@ -609,15 +609,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
609
609
) -> InterpResult < ' tcx , ( u128 , VariantIdx ) > {
610
610
trace ! ( "read_discriminant_value {:#?}" , rval. layout) ;
611
611
612
- let ( discr_kind, discr_index) = match rval. layout . variants {
612
+ let ( discr_layout , discr_kind, discr_index) = match rval. layout . variants {
613
613
layout:: Variants :: Single { index } => {
614
614
let discr_val = rval. layout . ty . discriminant_for_variant ( * self . tcx , index) . map_or (
615
615
index. as_u32 ( ) as u128 ,
616
616
|discr| discr. val ) ;
617
617
return Ok ( ( discr_val, index) ) ;
618
618
}
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) ,
621
626
} ;
622
627
623
628
// read raw discriminant value
@@ -634,7 +639,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
634
639
. map_err ( |_| err_unsup ! ( InvalidDiscriminant ( raw_discr. erase_tag( ) ) ) ) ?;
635
640
let real_discr = if discr_val. layout . ty . is_signed ( ) {
636
641
// 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
638
643
let sexted = sign_extend ( bits_discr, discr_val. layout . size ) as i128 ;
639
644
// and then zeroing with the typeck discriminant type
640
645
let discr_ty = rval. layout . ty
@@ -682,8 +687,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
682
687
( dataful_variant. as_u32 ( ) as u128 , dataful_variant)
683
688
} ,
684
689
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.
687
715
if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
688
716
let index = adjusted_discr as usize ;
689
717
assert_eq ! ( index as u128 , adjusted_discr) ;
0 commit comments