@@ -15,12 +15,13 @@ use rustc;
15
15
use rustc:: hir;
16
16
use rustc:: hir:: def_id:: DefId ;
17
17
use rustc:: middle:: region;
18
- use rustc:: mir:: { self , Location , Place , Mir } ;
18
+ use rustc:: mir:: { self , Location , Place , Mir , TerminatorKind } ;
19
19
use rustc:: ty:: TyCtxt ;
20
- use rustc:: ty:: RegionKind ;
20
+ use rustc:: ty:: { RegionKind , RegionVid } ;
21
21
use rustc:: ty:: RegionKind :: ReScope ;
22
22
23
23
use rustc_data_structures:: bitslice:: BitwiseOperator ;
24
+ use rustc_data_structures:: fx:: FxHashMap ;
24
25
use rustc_data_structures:: indexed_set:: IdxSet ;
25
26
use rustc_data_structures:: indexed_vec:: IndexVec ;
26
27
use rustc_data_structures:: sync:: Lrc ;
@@ -46,9 +47,103 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
46
47
root_scope : Option < region:: Scope > ,
47
48
48
49
borrow_set : Rc < BorrowSet < ' tcx > > ,
50
+ borrows_out_of_scope_at_location : FxHashMap < Location , Vec < BorrowIndex > > ,
49
51
50
52
/// NLL region inference context with which NLL queries should be resolved
51
- nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
53
+ _nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
54
+ }
55
+
56
+ fn precompute_borrows_out_of_scope < ' a , ' tcx > (
57
+ mir : & ' a Mir < ' tcx > ,
58
+ regioncx : & Rc < RegionInferenceContext < ' tcx > > ,
59
+ borrows_out_of_scope_at_location : & mut FxHashMap < Location , Vec < BorrowIndex > > ,
60
+ borrow_index : BorrowIndex ,
61
+ borrow_region : RegionVid ,
62
+ location : Location
63
+ ) {
64
+ // Start by dealing with the current location.
65
+ if !regioncx. region_contains_point ( borrow_region, location) {
66
+ borrows_out_of_scope_at_location
67
+ . entry ( location. clone ( ) )
68
+ . and_modify ( |m| m. push ( borrow_index) )
69
+ . or_insert ( vec ! [ borrow_index ] ) ;
70
+ }
71
+
72
+ let bb_data = & mir[ location. block ] ;
73
+ // If we are on the last statement, then check the terminator
74
+ // to determine which location to proceed to.
75
+ if location. statement_index == bb_data. statements . len ( ) - 1 {
76
+ if let Some ( ref terminator) = bb_data. terminator {
77
+ match terminator. kind {
78
+ TerminatorKind :: Goto { target } |
79
+ TerminatorKind :: FalseEdges { real_target : target, .. } |
80
+ TerminatorKind :: FalseUnwind { real_target : target, .. } => {
81
+ precompute_borrows_out_of_scope (
82
+ mir, regioncx, borrows_out_of_scope_at_location,
83
+ borrow_index, borrow_region, target. start_location ( )
84
+ ) ;
85
+ } ,
86
+ TerminatorKind :: SwitchInt { ref targets, .. } => {
87
+ for block in targets {
88
+ precompute_borrows_out_of_scope (
89
+ mir, regioncx, borrows_out_of_scope_at_location,
90
+ borrow_index, borrow_region, block. start_location ( )
91
+ ) ;
92
+ }
93
+ } ,
94
+ TerminatorKind :: Drop { target, unwind, .. } |
95
+ TerminatorKind :: DropAndReplace { target, unwind, .. } => {
96
+ precompute_borrows_out_of_scope (
97
+ mir, regioncx, borrows_out_of_scope_at_location,
98
+ borrow_index, borrow_region, target. start_location ( )
99
+ ) ;
100
+
101
+ if let Some ( unwind_block) = unwind {
102
+ precompute_borrows_out_of_scope (
103
+ mir, regioncx, borrows_out_of_scope_at_location,
104
+ borrow_index, borrow_region, unwind_block. start_location ( )
105
+ ) ;
106
+ }
107
+ } ,
108
+ TerminatorKind :: Call { ref destination, cleanup, .. } => {
109
+ if let Some ( ( _, block) ) = destination {
110
+ precompute_borrows_out_of_scope (
111
+ mir, regioncx, borrows_out_of_scope_at_location,
112
+ borrow_index, borrow_region, block. start_location ( )
113
+ ) ;
114
+ }
115
+
116
+ if let Some ( block) = cleanup {
117
+ precompute_borrows_out_of_scope (
118
+ mir, regioncx, borrows_out_of_scope_at_location,
119
+ borrow_index, borrow_region, block. start_location ( )
120
+ ) ;
121
+ }
122
+ } ,
123
+ TerminatorKind :: Assert { target, cleanup, .. } |
124
+ TerminatorKind :: Yield { resume : target, drop : cleanup, .. } => {
125
+ precompute_borrows_out_of_scope (
126
+ mir, regioncx, borrows_out_of_scope_at_location,
127
+ borrow_index, borrow_region, target. start_location ( )
128
+ ) ;
129
+
130
+ if let Some ( block) = cleanup {
131
+ precompute_borrows_out_of_scope (
132
+ mir, regioncx, borrows_out_of_scope_at_location,
133
+ borrow_index, borrow_region, block. start_location ( )
134
+ ) ;
135
+ }
136
+ } ,
137
+ _ => { } ,
138
+ } ;
139
+ } ;
140
+ // If we're not on the last statement, then go to the next
141
+ // statement in this block.
142
+ } else {
143
+ precompute_borrows_out_of_scope ( mir, regioncx, borrows_out_of_scope_at_location,
144
+ borrow_index, borrow_region,
145
+ location. successor_within_block ( ) ) ;
146
+ }
52
147
}
53
148
54
149
impl < ' a , ' gcx , ' tcx > Borrows < ' a , ' gcx , ' tcx > {
@@ -65,18 +160,28 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
65
160
region:: Scope :: CallSite ( tcx. hir . body ( body_id) . value . hir_id . local_id )
66
161
} ) ;
67
162
163
+ let mut borrows_out_of_scope_at_location = FxHashMap ( ) ;
164
+ for ( borrow_index, borrow_data) in borrow_set. borrows . iter_enumerated ( ) {
165
+ let borrow_region = borrow_data. region . to_region_vid ( ) ;
166
+ let location = borrow_set. borrows [ borrow_index] . reserve_location ;
167
+
168
+ precompute_borrows_out_of_scope ( mir, & nonlexical_regioncx,
169
+ & mut borrows_out_of_scope_at_location,
170
+ borrow_index, borrow_region, location) ;
171
+ }
172
+
68
173
Borrows {
69
174
tcx : tcx,
70
175
mir : mir,
71
176
borrow_set : borrow_set. clone ( ) ,
177
+ borrows_out_of_scope_at_location,
72
178
scope_tree,
73
179
root_scope,
74
- nonlexical_regioncx,
180
+ _nonlexical_regioncx : nonlexical_regioncx,
75
181
}
76
182
}
77
183
78
184
crate fn borrows ( & self ) -> & IndexVec < BorrowIndex , BorrowData < ' tcx > > { & self . borrow_set . borrows }
79
-
80
185
pub fn scope_tree ( & self ) -> & Lrc < region:: ScopeTree > { & self . scope_tree }
81
186
82
187
pub fn location ( & self , idx : BorrowIndex ) -> & Location {
@@ -89,23 +194,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
89
194
fn kill_loans_out_of_scope_at_location ( & self ,
90
195
sets : & mut BlockSets < BorrowIndex > ,
91
196
location : Location ) {
92
- let regioncx = & self . nonlexical_regioncx ;
93
-
94
197
// NOTE: The state associated with a given `location`
95
- // reflects the dataflow on entry to the statement. If it
96
- // does not contain `borrow_region`, then then that means
97
- // that the statement at ` location` kills the borrow .
198
+ // reflects the dataflow on entry to the statement.
199
+ // Iterate over each of the borrows that we've precomputed
200
+ // to have went out of scope at this location and kill them .
98
201
//
99
202
// We are careful always to call this function *before* we
100
203
// set up the gen-bits for the statement or
101
204
// termanator. That way, if the effect of the statement or
102
205
// terminator *does* introduce a new loan of the same
103
206
// region, then setting that gen-bit will override any
104
207
// potential kill introduced here.
105
- for ( borrow_index, borrow_data) in self . borrow_set . borrows . iter_enumerated ( ) {
106
- let borrow_region = borrow_data. region . to_region_vid ( ) ;
107
- if !regioncx. region_contains_point ( borrow_region, location) {
108
- sets. kill ( & borrow_index) ;
208
+ if let Some ( indices) = self . borrows_out_of_scope_at_location . get ( & location) {
209
+ for index in indices {
210
+ sets. kill ( & index) ;
109
211
}
110
212
}
111
213
}
0 commit comments