1
1
//! Functions concerning immediate values and operands, and reading from operands.
2
2
//! All high-level functions to read from memory work on operands as sources.
3
3
4
- use std:: convert:: TryInto ;
4
+ use std:: convert:: { TryInto , TryFrom } ;
5
5
6
6
use rustc:: { mir, ty} ;
7
7
use rustc:: ty:: layout:: {
8
- self , Size , LayoutOf , TyLayout , HasDataLayout , IntegerExt , VariantIdx ,
8
+ self , Size , LayoutOf , TyLayout , HasDataLayout , IntegerExt , PrimitiveExt , VariantIdx ,
9
9
} ;
10
10
11
11
use rustc:: mir:: interpret:: {
@@ -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
@@ -666,8 +671,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
666
671
ref niche_variants,
667
672
niche_start,
668
673
} => {
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 ( ) ;
671
676
let raw_discr = raw_discr. not_undef ( ) . map_err ( |_| {
672
677
err_unsup ! ( InvalidDiscriminant ( ScalarMaybeUndef :: Undef ) )
673
678
} ) ?;
@@ -682,18 +687,34 @@ 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) ;
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
691
712
. ty_adt_def( )
692
713
. expect( "tagged layout for non adt" )
693
714
. variants. len( ) ) ;
694
- ( adjusted_discr , VariantIdx :: from_usize ( index ) )
715
+ ( u128 :: from ( variant_index ) , VariantIdx :: from_u32 ( variant_index ) )
695
716
} else {
696
- ( dataful_variant. as_u32 ( ) as u128 , dataful_variant)
717
+ ( u128 :: from ( dataful_variant. as_u32 ( ) ) , dataful_variant)
697
718
}
698
719
} ,
699
720
}
0 commit comments