@@ -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 > > ,
@@ -158,68 +152,66 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
158152 borrow_region : RegionVid ,
159153 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 `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-
173155 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+ }
176181
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+ }
178188
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 ( ) ;
180195 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 )
182197 {
183- let kill_location = Location { block : bb , statement_index : kill_stmt } ;
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.
186201 debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, kill_location) ;
187202 self . borrows_out_of_scope_at_location
188203 . entry ( kill_location)
189204 . or_default ( )
190205 . push ( borrow_index) ;
191- continue ' preorder;
192- }
193206
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.
197208 continue ;
198209 }
199210
200211 // Add successor BBs to the work list, if necessary.
201- let bb_data = & self . body [ bb] ;
202- debug_assert ! ( hi == bb_data. statements. len( ) ) ;
203212 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) ;
223215 }
224216 }
225217 }
0 commit comments