@@ -6,7 +6,7 @@ use rustc_const_eval::const_eval::CheckAlignment;
6
6
use rustc_const_eval:: interpret:: { ConstValue , ImmTy , Immediate , InterpCx , Scalar } ;
7
7
use rustc_data_structures:: fx:: FxHashMap ;
8
8
use rustc_hir:: def:: DefKind ;
9
- use rustc_middle:: mir:: visit:: { MutVisitor , Visitor } ;
9
+ use rustc_middle:: mir:: visit:: { MutVisitor , NonMutatingUseContext , PlaceContext , Visitor } ;
10
10
use rustc_middle:: mir:: * ;
11
11
use rustc_middle:: ty:: layout:: TyAndLayout ;
12
12
use rustc_middle:: ty:: { self , ScalarInt , Ty , TyCtxt } ;
@@ -545,11 +545,29 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
545
545
if let Some ( value) = self . before_effect . get ( & ( location, * place) ) {
546
546
let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
547
547
* operand = self . make_operand ( * value, ty) ;
548
+ } else if !place. projection . is_empty ( ) {
549
+ self . super_operand ( operand, location)
548
550
}
549
551
}
550
552
Operand :: Constant ( _) => { }
551
553
}
552
554
}
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
+ }
553
571
}
554
572
555
573
struct OperandCollector < ' tcx , ' map , ' locals , ' a > {
@@ -560,17 +578,21 @@ struct OperandCollector<'tcx, 'map, 'locals, 'a> {
560
578
561
579
impl < ' tcx > Visitor < ' tcx > for OperandCollector < ' tcx , ' _ , ' _ , ' _ > {
562
580
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)
572
587
}
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) ;
574
596
}
575
597
}
576
598
}
0 commit comments