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