@@ -743,28 +743,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
743
743
744
744
Discriminant ( ref place) => {
745
745
let ty = self . place_ty ( place) ;
746
- let layout = self . layout_of ( ty) ?;
747
746
let place = self . eval_place ( place) ?;
748
747
let discr_val = self . read_discriminant_value ( place, ty) ?;
749
- match layout. variants {
750
- layout:: Variants :: Single { index } => {
751
- assert_eq ! ( discr_val, index as u128 ) ;
752
- }
753
- layout:: Variants :: Tagged { .. } |
754
- layout:: Variants :: NicheFilling { .. } => {
755
- if let ty:: TyAdt ( adt_def, _) = ty. sty {
756
- trace ! ( "Read discriminant {}, valid discriminants {:?}" , discr_val, adt_def. discriminants( * self . tcx) . collect:: <Vec <_>>( ) ) ;
757
- if adt_def. discriminants ( * self . tcx ) . all ( |v| {
758
- discr_val != v. val
759
- } )
760
- {
761
- return err ! ( InvalidDiscriminant ) ;
762
- }
763
- } else {
764
- bug ! ( "rustc only generates Rvalue::Discriminant for enums" ) ;
765
- }
766
- }
767
- }
768
748
self . write_primval ( dest, PrimVal :: Bytes ( discr_val) , dest_ty) ?;
769
749
}
770
750
}
@@ -837,13 +817,39 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
837
817
}
838
818
}
839
819
820
+ /// reads a tag and produces the corresponding variant index
821
+ pub fn read_discriminant_as_variant_index (
822
+ & mut self ,
823
+ place : Place ,
824
+ ty : Ty < ' tcx > ,
825
+ ) -> EvalResult < ' tcx , usize > {
826
+ let layout = self . layout_of ( ty) ?;
827
+ match layout. variants {
828
+ ty:: layout:: Variants :: Single { index } => Ok ( index) ,
829
+ ty:: layout:: Variants :: Tagged { .. } => {
830
+ let discr_val = self . read_discriminant_value ( place, ty) ?;
831
+ ty
832
+ . ty_adt_def ( )
833
+ . expect ( "tagged layout for non adt" )
834
+ . discriminants ( self . tcx . tcx )
835
+ . position ( |var| var. val == discr_val)
836
+ . ok_or_else ( || EvalErrorKind :: InvalidDiscriminant . into ( ) )
837
+ }
838
+ ty:: layout:: Variants :: NicheFilling { .. } => {
839
+ let discr_val = self . read_discriminant_value ( place, ty) ?;
840
+ assert_eq ! ( discr_val as usize as u128 , discr_val) ;
841
+ Ok ( discr_val as usize )
842
+ } ,
843
+ }
844
+ }
845
+
840
846
pub fn read_discriminant_value (
841
847
& mut self ,
842
848
place : Place ,
843
849
ty : Ty < ' tcx > ,
844
850
) -> EvalResult < ' tcx , u128 > {
845
851
let layout = self . layout_of ( ty) ?;
846
- // trace!("read_discriminant_value {:#?}", layout);
852
+ trace ! ( "read_discriminant_value {:#?}" , layout) ;
847
853
848
854
match layout. variants {
849
855
layout:: Variants :: Single { index } => {
@@ -854,13 +860,34 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
854
860
}
855
861
856
862
let ( discr_place, discr) = self . place_field ( place, mir:: Field :: new ( 0 ) , layout) ?;
863
+ trace ! ( "discr place: {:?}, {:?}" , discr_place, discr) ;
857
864
let raw_discr = self . value_to_primval ( ValTy {
858
865
value : self . read_place ( discr_place) ?,
859
866
ty : discr. ty
860
867
} ) ?;
861
868
let discr_val = match layout. variants {
862
869
layout:: Variants :: Single { .. } => bug ! ( ) ,
863
- layout:: Variants :: Tagged { .. } => raw_discr. to_bytes ( ) ?,
870
+ // FIXME: should we catch invalid discriminants here?
871
+ layout:: Variants :: Tagged { .. } => {
872
+ if discr. ty . is_signed ( ) {
873
+ let i = raw_discr. to_bytes ( ) ? as i128 ;
874
+ // going from layout tag type to typeck discriminant type
875
+ // requires first sign extending with the layout discriminant
876
+ let amt = 128 - discr. size . bits ( ) ;
877
+ let sexted = ( i << amt) >> amt;
878
+ // and then zeroing with the typeck discriminant type
879
+ let discr_ty = ty
880
+ . ty_adt_def ( ) . expect ( "tagged layout corresponds to adt" )
881
+ . repr
882
+ . discr_type ( ) ;
883
+ let discr_ty = layout:: Integer :: from_attr ( self . tcx . tcx , discr_ty) ;
884
+ let amt = 128 - discr_ty. size ( ) . bits ( ) ;
885
+ let truncatee = sexted as u128 ;
886
+ ( truncatee << amt) >> amt
887
+ } else {
888
+ raw_discr. to_bytes ( ) ?
889
+ }
890
+ } ,
864
891
layout:: Variants :: NicheFilling {
865
892
dataful_variant,
866
893
ref niche_variants,
@@ -910,11 +937,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
910
937
layout:: Abi :: Uninhabited ) ;
911
938
}
912
939
}
913
- layout:: Variants :: Tagged { .. } => {
940
+ layout:: Variants :: Tagged { ref discr , .. } => {
914
941
let discr_val = dest_ty. ty_adt_def ( ) . unwrap ( )
915
942
. discriminant_for_variant ( * self . tcx , variant_index)
916
943
. val ;
917
944
945
+ // raw discriminants for enums are isize or bigger during
946
+ // their computation, but the in-memory tag is the smallest possible
947
+ // representation
948
+ let size = discr. value . size ( self . tcx . tcx ) . bits ( ) ;
949
+ let amt = 128 - size;
950
+ let discr_val = ( discr_val << amt) >> amt;
951
+
918
952
let ( discr_dest, discr) = self . place_field ( dest, mir:: Field :: new ( 0 ) , layout) ?;
919
953
self . write_primval ( discr_dest, PrimVal :: Bytes ( discr_val) , discr. ty ) ?;
920
954
}
@@ -1145,19 +1179,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
1145
1179
_ if primval. is_undef ( ) => false ,
1146
1180
_ => bug ! ( "write_value_to_ptr: invalid ByVal layout: {:#?}" , layout)
1147
1181
} ;
1148
- self . memory . write_primval ( dest. to_ptr ( ) ? , dest_align, primval, layout. size . bytes ( ) , signed)
1182
+ self . memory . write_primval ( dest, dest_align, primval, layout. size . bytes ( ) , signed)
1149
1183
}
1150
1184
Value :: ByValPair ( a_val, b_val) => {
1151
- let ptr = dest. to_ptr ( ) ?;
1152
1185
trace ! ( "write_value_to_ptr valpair: {:#?}" , layout) ;
1153
1186
let ( a, b) = match layout. abi {
1154
1187
layout:: Abi :: ScalarPair ( ref a, ref b) => ( & a. value , & b. value ) ,
1155
1188
_ => bug ! ( "write_value_to_ptr: invalid ByValPair layout: {:#?}" , layout)
1156
1189
} ;
1157
1190
let ( a_size, b_size) = ( a. size ( & self ) , b. size ( & self ) ) ;
1158
- let a_ptr = ptr ;
1191
+ let a_ptr = dest ;
1159
1192
let b_offset = a_size. abi_align ( b. align ( & self ) ) ;
1160
- let b_ptr = ptr . offset ( b_offset. bytes ( ) , & self ) ?. into ( ) ;
1193
+ let b_ptr = dest . offset ( b_offset. bytes ( ) , & self ) ?. into ( ) ;
1161
1194
// TODO: What about signedess?
1162
1195
self . memory . write_primval ( a_ptr, dest_align, a_val, a_size. bytes ( ) , false ) ?;
1163
1196
self . memory . write_primval ( b_ptr, dest_align, b_val, b_size. bytes ( ) , false )
0 commit comments