@@ -743,28 +743,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
743743
744744 Discriminant ( ref place) => {
745745 let ty = self . place_ty ( place) ;
746- let layout = self . layout_of ( ty) ?;
747746 let place = self . eval_place ( place) ?;
748747 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- }
768748 self . write_primval ( dest, PrimVal :: Bytes ( discr_val) , dest_ty) ?;
769749 }
770750 }
@@ -837,13 +817,39 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
837817 }
838818 }
839819
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+
840846 pub fn read_discriminant_value (
841847 & mut self ,
842848 place : Place ,
843849 ty : Ty < ' tcx > ,
844850 ) -> EvalResult < ' tcx , u128 > {
845851 let layout = self . layout_of ( ty) ?;
846- // trace!("read_discriminant_value {:#?}", layout);
852+ trace ! ( "read_discriminant_value {:#?}" , layout) ;
847853
848854 match layout. variants {
849855 layout:: Variants :: Single { index } => {
@@ -854,13 +860,34 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
854860 }
855861
856862 let ( discr_place, discr) = self . place_field ( place, mir:: Field :: new ( 0 ) , layout) ?;
863+ trace ! ( "discr place: {:?}, {:?}" , discr_place, discr) ;
857864 let raw_discr = self . value_to_primval ( ValTy {
858865 value : self . read_place ( discr_place) ?,
859866 ty : discr. ty
860867 } ) ?;
861868 let discr_val = match layout. variants {
862869 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+ } ,
864891 layout:: Variants :: NicheFilling {
865892 dataful_variant,
866893 ref niche_variants,
@@ -910,11 +937,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
910937 layout:: Abi :: Uninhabited ) ;
911938 }
912939 }
913- layout:: Variants :: Tagged { .. } => {
940+ layout:: Variants :: Tagged { ref discr , .. } => {
914941 let discr_val = dest_ty. ty_adt_def ( ) . unwrap ( )
915942 . discriminant_for_variant ( * self . tcx , variant_index)
916943 . val ;
917944
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+
918952 let ( discr_dest, discr) = self . place_field ( dest, mir:: Field :: new ( 0 ) , layout) ?;
919953 self . write_primval ( discr_dest, PrimVal :: Bytes ( discr_val) , discr. ty ) ?;
920954 }
@@ -1145,19 +1179,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
11451179 _ if primval. is_undef ( ) => false ,
11461180 _ => bug ! ( "write_value_to_ptr: invalid ByVal layout: {:#?}" , layout)
11471181 } ;
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)
11491183 }
11501184 Value :: ByValPair ( a_val, b_val) => {
1151- let ptr = dest. to_ptr ( ) ?;
11521185 trace ! ( "write_value_to_ptr valpair: {:#?}" , layout) ;
11531186 let ( a, b) = match layout. abi {
11541187 layout:: Abi :: ScalarPair ( ref a, ref b) => ( & a. value , & b. value ) ,
11551188 _ => bug ! ( "write_value_to_ptr: invalid ByValPair layout: {:#?}" , layout)
11561189 } ;
11571190 let ( a_size, b_size) = ( a. size ( & self ) , b. size ( & self ) ) ;
1158- let a_ptr = ptr ;
1191+ let a_ptr = dest ;
11591192 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 ( ) ;
11611194 // TODO: What about signedess?
11621195 self . memory . write_primval ( a_ptr, dest_align, a_val, a_size. bytes ( ) , false ) ?;
11631196 self . memory . write_primval ( b_ptr, dest_align, b_val, b_size. bytes ( ) , false )
0 commit comments