@@ -240,19 +240,9 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
240240 prec. borrows_out_of_scope_at_location
241241}
242242
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-
253243struct PoloniusOutOfScopePrecomputer < ' a , ' tcx > {
254244 visited : BitSet < mir:: BasicBlock > ,
255- visit_stack : Vec < StackEntry > ,
245+ visit_stack : Vec < mir :: BasicBlock > ,
256246 body : & ' a Body < ' tcx > ,
257247 regioncx : & ' a RegionInferenceContext < ' tcx > ,
258248
@@ -327,7 +317,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
327317 & mut self ,
328318 loan_idx : BorrowIndex ,
329319 issuing_region : RegionVid ,
330- issued_location : Location ,
320+ first_location : Location ,
331321 ) {
332322 // Let's precompute the reachability set of the issuing region, via reachability on the
333323 // condensation graph. We can also early return when reaching regions that outlive free
@@ -373,61 +363,51 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
373363 }
374364 }
375365
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] ;
379368
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) ;
385377
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+ }
389382
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+ }
391389
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) {
397397 debug ! ( "loan {:?} gets killed at {:?}" , loan_idx, kill_location) ;
398398 self . loans_out_of_scope_at_location
399399 . entry ( kill_location)
400400 . or_default ( )
401401 . push ( loan_idx) ;
402- continue ;
403- }
404402
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.
408404 continue ;
409405 }
410406
411407 // Add successor BBs to the work list, if necessary.
412- let bb_data = & self . body [ bb] ;
413- debug_assert ! ( hi == bb_data. statements. len( ) ) ;
414408 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) ;
431411 }
432412 }
433413 }
@@ -439,8 +419,8 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
439419 }
440420
441421 /// 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.
444424 fn loan_kill_location ( & self , block : BasicBlock , start : usize , end : usize ) -> Option < Location > {
445425 for statement_index in start..=end {
446426 let location = Location { block, statement_index } ;
0 commit comments