1
1
use crate :: MirPass ;
2
2
use rustc_index:: vec:: IndexVec ;
3
3
use rustc_middle:: mir:: patch:: MirPatch ;
4
+ use rustc_middle:: mir:: visit:: NonUseContext :: VarDebugInfo ;
4
5
use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext } ;
5
6
use rustc_middle:: mir:: * ;
6
7
use rustc_middle:: ty:: TyCtxt ;
8
+
7
9
pub struct Derefer ;
8
10
9
11
pub struct DerefChecker < ' tcx > {
@@ -17,63 +19,68 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
17
19
self . tcx
18
20
}
19
21
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 ;
24
30
25
- let mut prev_temp: Option < Local > = None ;
31
+ let mut prev_temp: Option < Local > = None ;
26
32
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;
62
36
}
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) ;
67
75
}
68
-
69
- prev_temp = Some ( temp) ;
70
76
}
71
- }
72
77
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
+ }
77
84
}
78
85
}
79
86
}
@@ -92,5 +99,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
92
99
impl < ' tcx > MirPass < ' tcx > for Derefer {
93
100
fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
94
101
deref_finder ( tcx, body) ;
102
+ body. phase = MirPhase :: Derefered ;
95
103
}
96
104
}
0 commit comments