@@ -812,81 +812,80 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
812812 proj : ProjectionElem < VnIndex , Ty < ' tcx > > ,
813813 ) -> Option < ( PlaceTy < ' tcx > , VnIndex ) > {
814814 let projection_ty = place_ty. projection_ty ( self . tcx , proj) ;
815- let proj = match proj {
816- ProjectionElem :: Deref => {
817- if let Some ( Mutability :: Not ) = place_ty. ty . ref_mutability ( )
815+ let proj = proj. try_map ( Some , |_| ( ) ) ?;
816+
817+ if let ProjectionElem :: Deref = proj
818+ && !(
819+ // An immutable borrow `_x` always points to the same value for the
820+ // lifetime of the borrow, so we can merge all instances of `*_x`.
821+ place_ty. ty . ref_mutability ( ) == Some ( Mutability :: Not )
818822 && projection_ty. ty . is_freeze ( self . tcx , self . typing_env ( ) )
819- {
820- if let Value :: Address { base, projection, .. } = self . get ( value)
821- && let Some ( value) = self . dereference_address ( base, projection)
822- {
823- return Some ( ( projection_ty, value) ) ;
824- }
823+ )
824+ {
825+ return None ;
826+ }
825827
826- // An immutable borrow `_x` always points to the same value for the
827- // lifetime of the borrow, so we can merge all instances of `*_x`.
828- return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
829- } else {
830- return None ;
831- }
828+ match ( proj, self . get ( value) ) {
829+ ( ProjectionElem :: Deref , Value :: Address { base, projection, .. } )
830+ if let Some ( deref) = self . dereference_address ( base, projection) =>
831+ {
832+ return Some ( ( projection_ty, deref) ) ;
832833 }
833- ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
834- ProjectionElem :: Field ( f, _) => match self . get ( value) {
835- Value :: Aggregate ( _, fields) => return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ,
836- Value :: Union ( active, field) if active == f => return Some ( ( projection_ty, field) ) ,
837- Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) )
838- if let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
839- // This pass is not aware of control-flow, so we do not know whether the
840- // replacement we are doing is actually reachable. We could be in any arm of
841- // ```
842- // match Some(x) {
843- // Some(y) => /* stuff */,
844- // None => /* other */,
845- // }
846- // ```
847- //
848- // In surface rust, the current statement would be unreachable.
849- //
850- // However, from the reference chapter on enums and RFC 2195,
851- // accessing the wrong variant is not UB if the enum has repr.
852- // So it's not impossible for a series of MIR opts to generate
853- // a downcast to an inactive variant.
854- && written_variant == read_variant =>
855- {
856- return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
857- }
858- _ => ProjectionElem :: Field ( f, ( ) ) ,
859- } ,
860- ProjectionElem :: Index ( idx) => {
861- if let Value :: Repeat ( inner, _) = self . get ( value) {
862- return Some ( ( projection_ty, inner) ) ;
863- }
864- ProjectionElem :: Index ( idx)
834+ ( ProjectionElem :: Deref , _) => {
835+ return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
865836 }
866- ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
867- match self . get ( value) {
868- Value :: Repeat ( inner, _) => {
869- return Some ( ( projection_ty, inner) ) ;
870- }
871- Value :: Aggregate ( _, operands) => {
872- let offset = if from_end {
873- operands. len ( ) - offset as usize
874- } else {
875- offset as usize
876- } ;
877- let value = operands. get ( offset) . copied ( ) ?;
878- return Some ( ( projection_ty, value) ) ;
879- }
880- _ => { }
881- } ;
882- ProjectionElem :: ConstantIndex { offset, min_length, from_end }
837+ ( ProjectionElem :: Field ( f, _) , Value :: Aggregate ( _, fields) ) => {
838+ return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
883839 }
884- ProjectionElem :: Subslice { from , to , from_end } => {
885- ProjectionElem :: Subslice { from , to , from_end }
840+ ( ProjectionElem :: Field ( f , _ ) , Value :: Union ( active , field ) ) if active == f => {
841+ return Some ( ( projection_ty , field ) ) ;
886842 }
887- ProjectionElem :: OpaqueCast ( _) => ProjectionElem :: OpaqueCast ( ( ) ) ,
888- ProjectionElem :: UnwrapUnsafeBinder ( _) => ProjectionElem :: UnwrapUnsafeBinder ( ( ) ) ,
889- } ;
843+ (
844+ ProjectionElem :: Field ( f, _) ,
845+ Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) ) ,
846+ ) if let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
847+ // This pass is not aware of control-flow, so we do not know whether the
848+ // replacement we are doing is actually reachable. We could be in any arm of
849+ // ```
850+ // match Some(x) {
851+ // Some(y) => /* stuff */,
852+ // None => /* other */,
853+ // }
854+ // ```
855+ //
856+ // In surface rust, the current statement would be unreachable.
857+ //
858+ // However, from the reference chapter on enums and RFC 2195,
859+ // accessing the wrong variant is not UB if the enum has repr.
860+ // So it's not impossible for a series of MIR opts to generate
861+ // a downcast to an inactive variant.
862+ && written_variant == read_variant =>
863+ {
864+ return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
865+ }
866+ ( ProjectionElem :: Index ( _) , Value :: Repeat ( inner, _) ) => {
867+ return Some ( ( projection_ty, inner) ) ;
868+ }
869+ ( ProjectionElem :: ConstantIndex { .. } , Value :: Repeat ( inner, _) ) => {
870+ return Some ( ( projection_ty, inner) ) ;
871+ }
872+ (
873+ ProjectionElem :: ConstantIndex { offset, from_end : false , .. } ,
874+ Value :: Aggregate ( _, operands) ,
875+ ) => {
876+ let value = operands. get ( offset as usize ) . copied ( ) ?;
877+ return Some ( ( projection_ty, value) ) ;
878+ }
879+ (
880+ ProjectionElem :: ConstantIndex { offset, from_end : true , .. } ,
881+ Value :: Aggregate ( _, operands) ,
882+ ) => {
883+ let offset = operands. len ( ) . checked_sub ( offset as usize ) ?;
884+ let value = operands[ offset] ;
885+ return Some ( ( projection_ty, value) ) ;
886+ }
887+ _ => { }
888+ }
890889
891890 let value = self . insert ( projection_ty. ty , Value :: Projection ( value, proj) ) ;
892891 Some ( ( projection_ty, value) )
0 commit comments