@@ -125,15 +125,9 @@ pub struct Borrows<'a, 'tcx> {
125
125
borrows_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
126
126
}
127
127
128
- struct StackEntry {
129
- bb : mir:: BasicBlock ,
130
- lo : usize ,
131
- hi : usize ,
132
- }
133
-
134
128
struct OutOfScopePrecomputer < ' a , ' tcx > {
135
129
visited : BitSet < mir:: BasicBlock > ,
136
- visit_stack : Vec < StackEntry > ,
130
+ visit_stack : Vec < mir :: BasicBlock > ,
137
131
body : & ' a Body < ' tcx > ,
138
132
regioncx : & ' a RegionInferenceContext < ' tcx > ,
139
133
borrows_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
@@ -158,68 +152,66 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
158
152
borrow_region : RegionVid ,
159
153
first_location : Location ,
160
154
) {
161
- // We visit one BB at a time. The complication is that we may start in the
162
- // middle of the first BB visited (the one containing `first_location`), in which
163
- // case we may have to later on process the first part of that BB if there
164
- // is a path back to its start.
165
-
166
- // For visited BBs, we record the index of the first statement processed.
167
- // (In fully processed BBs this index is 0.) Note also that we add BBs to
168
- // `visited` once they are added to `stack`, before they are actually
169
- // processed, because this avoids the need to look them up again on
170
- // completion.
171
- self . visited . insert ( first_location. block ) ;
172
-
173
155
let first_block = first_location. block ;
174
- let mut first_lo = first_location. statement_index ;
175
- let first_hi = self . body [ first_block] . statements . len ( ) ;
156
+ let first_bb_data = & self . body . basic_blocks [ first_block] ;
157
+
158
+ // This is the first block, we only want to visit it from the creation of the borrow at
159
+ // `first_location`.
160
+ let first_lo = first_location. statement_index ;
161
+ let first_hi = first_bb_data. statements . len ( ) ;
162
+
163
+ if let Some ( kill_stmt) = self . regioncx . first_non_contained_inclusive (
164
+ borrow_region,
165
+ first_block,
166
+ first_lo,
167
+ first_hi,
168
+ ) {
169
+ let kill_location = Location { block : first_block, statement_index : kill_stmt } ;
170
+ // If region does not contain a point at the location, then add to list and skip
171
+ // successor locations.
172
+ debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, kill_location) ;
173
+ self . borrows_out_of_scope_at_location
174
+ . entry ( kill_location)
175
+ . or_default ( )
176
+ . push ( borrow_index) ;
177
+
178
+ // The borrow is already dead, there is no need to visit other blocks.
179
+ return ;
180
+ }
176
181
177
- self . visit_stack . push ( StackEntry { bb : first_block, lo : first_lo, hi : first_hi } ) ;
182
+ // The borrow is not dead. Add successor BBs to the work list, if necessary.
183
+ for succ_bb in first_bb_data. terminator ( ) . successors ( ) {
184
+ if self . visited . insert ( succ_bb) {
185
+ self . visit_stack . push ( succ_bb) ;
186
+ }
187
+ }
178
188
179
- ' preorder: while let Some ( StackEntry { bb, lo, hi } ) = self . visit_stack . pop ( ) {
189
+ // We may end up visiting `first_block` again. This is not an issue: we know at this point
190
+ // that it does not kill the borrow in the `first_lo..=first_hi` range, so checking the
191
+ // `0..first_lo` range and the `0..first_hi` range give the same result.
192
+ while let Some ( block) = self . visit_stack . pop ( ) {
193
+ let bb_data = & self . body [ block] ;
194
+ let num_stmts = bb_data. statements . len ( ) ;
180
195
if let Some ( kill_stmt) =
181
- self . regioncx . first_non_contained_inclusive ( borrow_region, bb , lo , hi )
196
+ self . regioncx . first_non_contained_inclusive ( borrow_region, block , 0 , num_stmts )
182
197
{
183
- let kill_location = Location { block : bb , statement_index : kill_stmt } ;
198
+ let kill_location = Location { block, statement_index : kill_stmt } ;
184
199
// If region does not contain a point at the location, then add to list and skip
185
200
// successor locations.
186
201
debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, kill_location) ;
187
202
self . borrows_out_of_scope_at_location
188
203
. entry ( kill_location)
189
204
. or_default ( )
190
205
. push ( borrow_index) ;
191
- continue ' preorder;
192
- }
193
206
194
- // If we process the first part of the first basic block (i.e. we encounter that block
195
- // for the second time), we no longer have to visit its successors again.
196
- if bb == first_block && hi != first_hi {
207
+ // We killed the borrow, so we do not visit this block's successors.
197
208
continue ;
198
209
}
199
210
200
211
// Add successor BBs to the work list, if necessary.
201
- let bb_data = & self . body [ bb] ;
202
- debug_assert ! ( hi == bb_data. statements. len( ) ) ;
203
212
for succ_bb in bb_data. terminator ( ) . successors ( ) {
204
- if !self . visited . insert ( succ_bb) {
205
- if succ_bb == first_block && first_lo > 0 {
206
- // `succ_bb` has been seen before. If it wasn't
207
- // fully processed, add its first part to `stack`
208
- // for processing.
209
- self . visit_stack . push ( StackEntry { bb : succ_bb, lo : 0 , hi : first_lo - 1 } ) ;
210
-
211
- // And update this entry with 0, to represent the
212
- // whole BB being processed.
213
- first_lo = 0 ;
214
- }
215
- } else {
216
- // succ_bb hasn't been seen before. Add it to
217
- // `stack` for processing.
218
- self . visit_stack . push ( StackEntry {
219
- bb : succ_bb,
220
- lo : 0 ,
221
- hi : self . body [ succ_bb] . statements . len ( ) ,
222
- } ) ;
213
+ if self . visited . insert ( succ_bb) {
214
+ self . visit_stack . push ( succ_bb) ;
223
215
}
224
216
}
225
217
}
0 commit comments