11use crate :: MirPass ;
22use rustc_index:: vec:: IndexVec ;
33use rustc_middle:: mir:: patch:: MirPatch ;
4+ use rustc_middle:: mir:: visit:: NonUseContext :: VarDebugInfo ;
45use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext } ;
56use rustc_middle:: mir:: * ;
67use rustc_middle:: ty:: TyCtxt ;
8+
79pub struct Derefer ;
810
911pub struct DerefChecker < ' tcx > {
@@ -17,63 +19,68 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
1719 self . tcx
1820 }
1921
20- fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , loc : Location ) {
21- let mut place_local = place. local ;
22- let mut last_len = 0 ;
23- let mut last_deref_idx = 0 ;
22+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , cntxt : PlaceContext , loc : Location ) {
23+ if !place. projection . is_empty ( )
24+ && cntxt != PlaceContext :: NonUse ( VarDebugInfo )
25+ && place. projection [ 1 ..] . contains ( & ProjectionElem :: Deref )
26+ {
27+ let mut place_local = place. local ;
28+ let mut last_len = 0 ;
29+ let mut last_deref_idx = 0 ;
2430
25- let mut prev_temp: Option < Local > = None ;
31+ let mut prev_temp: Option < Local > = None ;
2632
27- for ( idx, ( p_ref, p_elem) ) in place. iter_projections ( ) . enumerate ( ) {
28- if p_elem == ProjectionElem :: Deref && !p_ref. projection . is_empty ( ) {
29- last_deref_idx = idx;
30- }
31- }
32-
33- for ( idx, ( p_ref, p_elem) ) in place. iter_projections ( ) . enumerate ( ) {
34- if p_elem == ProjectionElem :: Deref && !p_ref. projection . is_empty ( ) {
35- let ty = p_ref. ty ( & self . local_decls , self . tcx ) . ty ;
36- let temp = self . patcher . new_local_with_info (
37- ty,
38- self . local_decls [ p_ref. local ] . source_info . span ,
39- Some ( Box :: new ( LocalInfo :: DerefTemp ) ) ,
40- ) ;
41-
42- self . patcher . add_statement ( loc, StatementKind :: StorageLive ( temp) ) ;
43-
44- // We are adding current p_ref's projections to our
45- // temp value, excluding projections we already covered.
46- let deref_place = Place :: from ( place_local)
47- . project_deeper ( & p_ref. projection [ last_len..] , self . tcx ) ;
48-
49- self . patcher . add_assign (
50- loc,
51- Place :: from ( temp) ,
52- Rvalue :: Use ( Operand :: Move ( deref_place) ) ,
53- ) ;
54- place_local = temp;
55- last_len = p_ref. projection . len ( ) ;
56-
57- // Change `Place` only if we are actually at the Place's last deref
58- if idx == last_deref_idx {
59- let temp_place =
60- Place :: from ( temp) . project_deeper ( & place. projection [ idx..] , self . tcx ) ;
61- * place = temp_place;
33+ for ( idx, elem) in place. projection [ 0 ..] . iter ( ) . enumerate ( ) {
34+ if * elem == ProjectionElem :: Deref {
35+ last_deref_idx = idx;
6236 }
63-
64- // We are destroying the previous temp since it's no longer used.
65- if let Some ( prev_temp) = prev_temp {
66- self . patcher . add_statement ( loc, StatementKind :: StorageDead ( prev_temp) ) ;
37+ }
38+ for ( idx, ( p_ref, p_elem) ) in place. iter_projections ( ) . enumerate ( ) {
39+ if !p_ref. projection . is_empty ( ) && p_elem == ProjectionElem :: Deref {
40+ let ty = p_ref. ty ( & self . local_decls , self . tcx ) . ty ;
41+ let temp = self . patcher . new_local_with_info (
42+ ty,
43+ self . local_decls [ p_ref. local ] . source_info . span ,
44+ Some ( Box :: new ( LocalInfo :: DerefTemp ) ) ,
45+ ) ;
46+
47+ self . patcher . add_statement ( loc, StatementKind :: StorageLive ( temp) ) ;
48+
49+ // We are adding current p_ref's projections to our
50+ // temp value, excluding projections we already covered.
51+ let deref_place = Place :: from ( place_local)
52+ . project_deeper ( & p_ref. projection [ last_len..] , self . tcx ) ;
53+
54+ self . patcher . add_assign (
55+ loc,
56+ Place :: from ( temp) ,
57+ Rvalue :: Use ( Operand :: Move ( deref_place) ) ,
58+ ) ;
59+ place_local = temp;
60+ last_len = p_ref. projection . len ( ) ;
61+
62+ // Change `Place` only if we are actually at the Place's last deref
63+ if idx == last_deref_idx {
64+ let temp_place =
65+ Place :: from ( temp) . project_deeper ( & place. projection [ idx..] , self . tcx ) ;
66+ * place = temp_place;
67+ }
68+
69+ // We are destroying the previous temp since it's no longer used.
70+ if let Some ( prev_temp) = prev_temp {
71+ self . patcher . add_statement ( loc, StatementKind :: StorageDead ( prev_temp) ) ;
72+ }
73+
74+ prev_temp = Some ( temp) ;
6775 }
68-
69- prev_temp = Some ( temp) ;
7076 }
71- }
7277
73- // Since we won't be able to reach final temp, we destroy it outside the loop.
74- if let Some ( prev_temp) = prev_temp {
75- let last_loc = Location { block : loc. block , statement_index : loc. statement_index + 1 } ;
76- self . patcher . add_statement ( last_loc, StatementKind :: StorageDead ( prev_temp) ) ;
78+ // Since we won't be able to reach final temp, we destroy it outside the loop.
79+ if let Some ( prev_temp) = prev_temp {
80+ let last_loc =
81+ Location { block : loc. block , statement_index : loc. statement_index + 1 } ;
82+ self . patcher . add_statement ( last_loc, StatementKind :: StorageDead ( prev_temp) ) ;
83+ }
7784 }
7885 }
7986}
@@ -92,5 +99,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
9299impl < ' tcx > MirPass < ' tcx > for Derefer {
93100 fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
94101 deref_finder ( tcx, body) ;
102+ body. phase = MirPhase :: Derefered ;
95103 }
96104}
0 commit comments