@@ -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 , Ty , TyCtxt } ;
@@ -579,11 +579,29 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
579
579
Operand :: Copy ( place) | Operand :: Move ( place) => {
580
580
if let Some ( value) = self . before_effect . get ( & ( location, * place) ) {
581
581
* operand = self . make_operand ( value. clone ( ) ) ;
582
+ } else if !place. projection . is_empty ( ) {
583
+ self . super_operand ( operand, location)
582
584
}
583
585
}
584
586
_ => ( ) ,
585
587
}
586
588
}
589
+
590
+ fn process_projection_elem (
591
+ & mut self ,
592
+ elem : PlaceElem < ' tcx > ,
593
+ location : Location ,
594
+ ) -> Option < PlaceElem < ' tcx > > {
595
+ if let PlaceElem :: Index ( local) = elem
596
+ && let Some ( value) = self . before_effect . get ( & ( location, local. into ( ) ) )
597
+ && let Ok ( offset) = value. 0 . to_target_usize ( & self . tcx )
598
+ && let Some ( min_length) = offset. checked_add ( 1 )
599
+ {
600
+ Some ( PlaceElem :: ConstantIndex { offset, min_length, from_end : false } )
601
+ } else {
602
+ None
603
+ }
604
+ }
587
605
}
588
606
589
607
pub ( crate ) struct OperandCollector < ' tcx , ' map , ' a > {
@@ -594,17 +612,21 @@ pub(crate) struct OperandCollector<'tcx, 'map, 'a> {
594
612
595
613
impl < ' tcx , ' map , ' a > Visitor < ' tcx > for OperandCollector < ' tcx , ' map , ' a > {
596
614
fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
597
- match operand {
598
- Operand :: Copy ( place) | Operand :: Move ( place) => {
599
- match self . state . get ( place. as_ref ( ) , self . map ) {
600
- FlatSet :: Top => ( ) ,
601
- FlatSet :: Elem ( value) => {
602
- self . visitor . before_effect . insert ( ( location, * place) , value) ;
603
- }
604
- FlatSet :: Bottom => ( ) ,
605
- }
615
+ if let Some ( place) = operand. place ( ) {
616
+ if let FlatSet :: Elem ( value) = self . state . get ( place. as_ref ( ) , self . map ) {
617
+ self . visitor . before_effect . insert ( ( location, place) , value) ;
618
+ } else if !place. projection . is_empty ( ) {
619
+ // Try to propagate into `Index` projections.
620
+ self . super_operand ( operand, location)
606
621
}
607
- _ => ( ) ,
622
+ }
623
+ }
624
+
625
+ fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , location : Location ) {
626
+ if let PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ) = ctxt
627
+ && let FlatSet :: Elem ( value) = self . state . get ( local. into ( ) , self . map )
628
+ {
629
+ self . visitor . before_effect . insert ( ( location, local. into ( ) ) , value) ;
608
630
}
609
631
}
610
632
}
0 commit comments