@@ -125,15 +125,9 @@ pub struct Borrows<'a, 'tcx> {
125125 borrows_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
126126}
127127
128- struct StackEntry {
129- bb : mir:: BasicBlock ,
130- lo : usize ,
131- hi : usize ,
132- }
133-
134128struct OutOfScopePrecomputer < ' a , ' tcx > {
135129 visited : BitSet < mir:: BasicBlock > ,
136- visit_stack : Vec < StackEntry > ,
130+ visit_stack : Vec < mir :: BasicBlock > ,
137131 body : & ' a Body < ' tcx > ,
138132 regioncx : & ' a RegionInferenceContext < ' tcx > ,
139133 borrows_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
@@ -156,73 +150,68 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
156150 & mut self ,
157151 borrow_index : BorrowIndex ,
158152 borrow_region : RegionVid ,
159- location : Location ,
153+ first_location : Location ,
160154 ) {
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 `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 ( location. block ) ;
172-
173- let mut first_lo = location. statement_index ;
174- let first_hi = self . body [ location. block ] . statements . len ( ) ;
175-
176- self . visit_stack . push ( StackEntry { bb : location. block , lo : first_lo, hi : first_hi } ) ;
177-
178- while let Some ( StackEntry { bb, lo, hi } ) = self . visit_stack . pop ( ) {
179- // If we process the first part of the first basic block (i.e. we encounter that block
180- // for the second time), we no longer have to visit its successors again.
181- let mut finished_early = bb == location. block && hi != first_hi;
182- for i in lo..=hi {
183- let location = Location { block : bb, statement_index : i } ;
155+ let first_block = first_location. block ;
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+ }
181+
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+ }
188+
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 ( ) ;
195+ if let Some ( kill_stmt) =
196+ self . regioncx . first_non_contained_inclusive ( borrow_region, block, 0 , num_stmts)
197+ {
198+ let kill_location = Location { block, statement_index : kill_stmt } ;
184199 // If region does not contain a point at the location, then add to list and skip
185200 // successor locations.
186- if !self . regioncx . region_contains ( borrow_region, location) {
187- debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
188- self . borrows_out_of_scope_at_location
189- . entry ( location)
190- . or_default ( )
191- . push ( borrow_index) ;
192- finished_early = true ;
193- break ;
194- }
201+ debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, kill_location) ;
202+ self . borrows_out_of_scope_at_location
203+ . entry ( kill_location)
204+ . or_default ( )
205+ . push ( borrow_index) ;
206+
207+ // We killed the borrow, so we do not visit this block's successors.
208+ continue ;
195209 }
196210
197- if !finished_early {
198- // Add successor BBs to the work list, if necessary.
199- let bb_data = & self . body [ bb] ;
200- debug_assert ! ( hi == bb_data. statements. len( ) ) ;
201- for succ_bb in bb_data. terminator ( ) . successors ( ) {
202- if !self . visited . insert ( succ_bb) {
203- if succ_bb == location. block && first_lo > 0 {
204- // `succ_bb` has been seen before. If it wasn't
205- // fully processed, add its first part to `stack`
206- // for processing.
207- self . visit_stack . push ( StackEntry {
208- bb : succ_bb,
209- lo : 0 ,
210- hi : first_lo - 1 ,
211- } ) ;
212-
213- // And update this entry with 0, to represent the
214- // whole BB being processed.
215- first_lo = 0 ;
216- }
217- } else {
218- // succ_bb hasn't been seen before. Add it to
219- // `stack` for processing.
220- self . visit_stack . push ( StackEntry {
221- bb : succ_bb,
222- lo : 0 ,
223- hi : self . body [ succ_bb] . statements . len ( ) ,
224- } ) ;
225- }
211+ // Add successor BBs to the work list, if necessary.
212+ for succ_bb in bb_data. terminator ( ) . successors ( ) {
213+ if self . visited . insert ( succ_bb) {
214+ self . visit_stack . push ( succ_bb) ;
226215 }
227216 }
228217 }
0 commit comments