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