@@ -6,7 +6,7 @@ use rustc_const_eval::const_eval::CheckAlignment;
66use rustc_const_eval:: interpret:: { ConstValue , ImmTy , Immediate , InterpCx , Scalar } ;
77use rustc_data_structures:: fx:: FxHashMap ;
88use rustc_hir:: def:: DefKind ;
9- use rustc_middle:: mir:: visit:: { MutVisitor , Visitor } ;
9+ use rustc_middle:: mir:: visit:: { MutVisitor , NonMutatingUseContext , PlaceContext , Visitor } ;
1010use rustc_middle:: mir:: * ;
1111use rustc_middle:: ty:: layout:: TyAndLayout ;
1212use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
@@ -545,11 +545,29 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
545545 if let Some ( value) = self . before_effect . get ( & ( location, * place) ) {
546546 let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
547547 * operand = self . make_operand ( * value, ty) ;
548+ } else if !place. projection . is_empty ( ) {
549+ self . super_operand ( operand, location)
548550 }
549551 }
550552 Operand :: Constant ( _) => { }
551553 }
552554 }
555+
556+ fn process_projection_elem (
557+ & mut self ,
558+ elem : PlaceElem < ' tcx > ,
559+ location : Location ,
560+ ) -> Option < PlaceElem < ' tcx > > {
561+ if let PlaceElem :: Index ( local) = elem
562+ && let Some ( value) = self . before_effect . get ( & ( location, local. into ( ) ) )
563+ && let Ok ( offset) = value. try_to_target_usize ( self . tcx )
564+ && let Some ( min_length) = offset. checked_add ( 1 )
565+ {
566+ Some ( PlaceElem :: ConstantIndex { offset, min_length, from_end : false } )
567+ } else {
568+ None
569+ }
570+ }
553571}
554572
555573struct OperandCollector < ' tcx , ' map , ' locals , ' a > {
@@ -560,17 +578,21 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> {
560578
561579impl < ' tcx > Visitor < ' tcx > for OperandCollector < ' tcx , ' _ , ' _ , ' _ > {
562580 fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
563- match operand {
564- Operand :: Copy ( place) | Operand :: Move ( place) => {
565- match self . state . get ( place. as_ref ( ) , self . map ) {
566- FlatSet :: Top => ( ) ,
567- FlatSet :: Elem ( value) => {
568- self . visitor . before_effect . insert ( ( location, * place) , value) ;
569- }
570- FlatSet :: Bottom => ( ) ,
571- }
581+ if let Some ( place) = operand. place ( ) {
582+ if let FlatSet :: Elem ( value) = self . state . get ( place. as_ref ( ) , self . map ) {
583+ self . visitor . before_effect . insert ( ( location, place) , value) ;
584+ } else if !place. projection . is_empty ( ) {
585+ // Try to propagate into `Index` projections.
586+ self . super_operand ( operand, location)
572587 }
573- _ => ( ) ,
588+ }
589+ }
590+
591+ fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , location : Location ) {
592+ if let PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ) = ctxt
593+ && let FlatSet :: Elem ( value) = self . state . get ( local. into ( ) , self . map )
594+ {
595+ self . visitor . before_effect . insert ( ( location, local. into ( ) ) , value) ;
574596 }
575597 }
576598}
0 commit comments