@@ -240,19 +240,9 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
240
240
prec. borrows_out_of_scope_at_location
241
241
}
242
242
243
- /// An entry in the CFG walk stack of the scope computation, recording visited statements within a
244
- /// block, in case of cycles requiring revisiting the same block but at earlier points.
245
- // FIXME: `precompute_borrows_out_of_scope` has stopped using this structure, and a similar
246
- // reorganizing of `precompute_loans_out_of_scope` could also avoid it.
247
- struct StackEntry {
248
- bb : mir:: BasicBlock ,
249
- lo : usize ,
250
- hi : usize ,
251
- }
252
-
253
243
struct PoloniusOutOfScopePrecomputer < ' a , ' tcx > {
254
244
visited : BitSet < mir:: BasicBlock > ,
255
- visit_stack : Vec < StackEntry > ,
245
+ visit_stack : Vec < mir :: BasicBlock > ,
256
246
body : & ' a Body < ' tcx > ,
257
247
regioncx : & ' a RegionInferenceContext < ' tcx > ,
258
248
@@ -327,7 +317,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
327
317
& mut self ,
328
318
loan_idx : BorrowIndex ,
329
319
issuing_region : RegionVid ,
330
- issued_location : Location ,
320
+ first_location : Location ,
331
321
) {
332
322
// Let's precompute the reachability set of the issuing region, via reachability on the
333
323
// condensation graph. We can also early return when reaching regions that outlive free
@@ -373,61 +363,51 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
373
363
}
374
364
}
375
365
376
- // We visit one BB at a time. The complication is that we may start in the middle of the
377
- // first BB visited (the one containing `issued_location`), in which case we may have to
378
- // later on process the first part of that BB if there is a path back to its start.
366
+ let first_block = first_location. block ;
367
+ let first_bb_data = & self . body . basic_blocks [ first_block] ;
379
368
380
- // For visited BBs, we record the index of the first statement processed. (In fully
381
- // processed BBs this index is 0.) Note also that we add BBs to `visited` once they are
382
- // added to `stack`, before they are actually processed, because this avoids the need to
383
- // look them up again on completion.
384
- self . visited . insert ( issued_location. block ) ;
369
+ // The first block we visit is the one where the loan is issued, starting from the statement
370
+ // where the loan is issued: at `first_location`.
371
+ let first_lo = first_location. statement_index ;
372
+ let first_hi = first_bb_data. statements . len ( ) ;
373
+
374
+ if let Some ( kill_location) = self . loan_kill_location ( first_block, first_lo, first_hi) {
375
+ debug ! ( "loan {:?} gets killed at {:?}" , loan_idx, kill_location) ;
376
+ self . loans_out_of_scope_at_location . entry ( kill_location) . or_default ( ) . push ( loan_idx) ;
385
377
386
- let first_block = issued_location. block ;
387
- let mut first_lo = issued_location. statement_index ;
388
- let first_hi = self . body [ issued_location. block ] . statements . len ( ) ;
378
+ // The loan dies within the first block, we're done and can early return.
379
+ self . reachability . clear ( ) ;
380
+ return ;
381
+ }
389
382
390
- self . visit_stack . push ( StackEntry { bb : issued_location. block , lo : first_lo, hi : first_hi } ) ;
383
+ // The loan is not dead. Add successor BBs to the work list, if necessary.
384
+ for succ_bb in first_bb_data. terminator ( ) . successors ( ) {
385
+ if self . visited . insert ( succ_bb) {
386
+ self . visit_stack . push ( succ_bb) ;
387
+ }
388
+ }
391
389
392
- while let Some ( StackEntry { bb, lo, hi } ) = self . visit_stack . pop ( ) {
393
- // Check whether the issuing region can reach local regions that are live at this point.
394
- // If not, then the loan is killed at this point and goes out of scope. We also can skip
395
- // visiting successor locations.
396
- if let Some ( kill_location) = self . loan_kill_location ( bb, lo, hi) {
390
+ // We may end up visiting `first_block` again. This is not an issue: we know at this point
391
+ // that the loan is not killed in the `first_lo..=first_hi` range, so checking the
392
+ // `0..first_lo` range and the `0..first_hi` range gives the same result.
393
+ while let Some ( block) = self . visit_stack . pop ( ) {
394
+ let bb_data = & self . body [ block] ;
395
+ let num_stmts = bb_data. statements . len ( ) ;
396
+ if let Some ( kill_location) = self . loan_kill_location ( block, 0 , num_stmts) {
397
397
debug ! ( "loan {:?} gets killed at {:?}" , loan_idx, kill_location) ;
398
398
self . loans_out_of_scope_at_location
399
399
. entry ( kill_location)
400
400
. or_default ( )
401
401
. push ( loan_idx) ;
402
- continue ;
403
- }
404
402
405
- // If we process the first part of the first basic block (i.e. we encounter that block
406
- // for the second time), we no longer have to visit its successors again.
407
- if bb == first_block && hi != first_hi {
403
+ // The loan dies within this block, so we don't need to visit its successors.
408
404
continue ;
409
405
}
410
406
411
407
// Add successor BBs to the work list, if necessary.
412
- let bb_data = & self . body [ bb] ;
413
- debug_assert ! ( hi == bb_data. statements. len( ) ) ;
414
408
for succ_bb in bb_data. terminator ( ) . successors ( ) {
415
- if !self . visited . insert ( succ_bb) {
416
- if succ_bb == first_block && first_lo > 0 {
417
- // `succ_bb` has been seen before. If it wasn't fully processed, add its
418
- // first part to the stack for processing.
419
- self . visit_stack . push ( StackEntry { bb : succ_bb, lo : 0 , hi : first_lo - 1 } ) ;
420
-
421
- // And update this entry with 0, to represent the whole BB being processed.
422
- first_lo = 0 ;
423
- }
424
- } else {
425
- // `succ_bb` hasn't been seen before. Add it to the stack for processing.
426
- self . visit_stack . push ( StackEntry {
427
- bb : succ_bb,
428
- lo : 0 ,
429
- hi : self . body [ succ_bb] . statements . len ( ) ,
430
- } ) ;
409
+ if self . visited . insert ( succ_bb) {
410
+ self . visit_stack . push ( succ_bb) ;
431
411
}
432
412
}
433
413
}
@@ -439,8 +419,8 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
439
419
}
440
420
441
421
/// Returns the lowest statement in `start..=end`, where the loan goes out of scope, if any.
442
- /// This will be the statement where the issuing region can't reach any of the regions live at
443
- /// this point.
422
+ /// This is the statement where the issuing region can't reach any of the regions that are live
423
+ /// at this point.
444
424
fn loan_kill_location ( & self , block : BasicBlock , start : usize , end : usize ) -> Option < Location > {
445
425
for statement_index in start..=end {
446
426
let location = Location { block, statement_index } ;
0 commit comments