@@ -11,7 +11,6 @@ use crate::borrow_check::{
1111use crate :: dataflow:: { self , fmt:: DebugWithContext , GenKill } ;
1212
1313use std:: fmt;
14- use std:: rc:: Rc ;
1514
1615rustc_index:: newtype_index! {
1716 pub struct BorrowIndex {
@@ -30,132 +29,136 @@ pub struct Borrows<'a, 'tcx> {
3029 tcx : TyCtxt < ' tcx > ,
3130 body : & ' a Body < ' tcx > ,
3231
33- borrow_set : Rc < BorrowSet < ' tcx > > ,
32+ borrow_set : & ' a BorrowSet < ' tcx > ,
3433 borrows_out_of_scope_at_location : FxHashMap < Location , Vec < BorrowIndex > > ,
35-
36- /// NLL region inference context with which NLL queries should be resolved
37- _nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
3834}
3935
4036struct StackEntry {
4137 bb : mir:: BasicBlock ,
4238 lo : usize ,
4339 hi : usize ,
44- first_part_only : bool ,
4540}
4641
47- fn precompute_borrows_out_of_scope < ' tcx > (
48- body : & Body < ' tcx > ,
49- regioncx : & Rc < RegionInferenceContext < ' tcx > > ,
50- borrows_out_of_scope_at_location : & mut FxHashMap < Location , Vec < BorrowIndex > > ,
51- borrow_index : BorrowIndex ,
52- borrow_region : RegionVid ,
53- location : Location ,
54- ) {
55- // We visit one BB at a time. The complication is that we may start in the
56- // middle of the first BB visited (the one containing `location`), in which
57- // case we may have to later on process the first part of that BB if there
58- // is a path back to its start.
59-
60- // For visited BBs, we record the index of the first statement processed.
61- // (In fully processed BBs this index is 0.) Note also that we add BBs to
62- // `visited` once they are added to `stack`, before they are actually
63- // processed, because this avoids the need to look them up again on
64- // completion.
65- let mut visited = FxHashMap :: default ( ) ;
66- visited. insert ( location. block , location. statement_index ) ;
67-
68- let mut stack = vec ! [ ] ;
69- stack. push ( StackEntry {
70- bb : location. block ,
71- lo : location. statement_index ,
72- hi : body[ location. block ] . statements . len ( ) ,
73- first_part_only : false ,
74- } ) ;
75-
76- while let Some ( StackEntry { bb, lo, hi, first_part_only } ) = stack. pop ( ) {
77- let mut finished_early = first_part_only;
78- for i in lo..=hi {
79- let location = Location { block : bb, statement_index : i } ;
80- // If region does not contain a point at the location, then add to list and skip
81- // successor locations.
82- if !regioncx. region_contains ( borrow_region, location) {
83- debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
84- borrows_out_of_scope_at_location. entry ( location) . or_default ( ) . push ( borrow_index) ;
85- finished_early = true ;
86- break ;
87- }
42+ struct OutOfScopePrecomputer < ' a , ' tcx > {
43+ visited : BitSet < mir:: BasicBlock > ,
44+ visit_stack : Vec < StackEntry > ,
45+ body : & ' a Body < ' tcx > ,
46+ regioncx : & ' a RegionInferenceContext < ' tcx > ,
47+ borrows_out_of_scope_at_location : FxHashMap < Location , Vec < BorrowIndex > > ,
48+ }
49+
50+ impl < ' a , ' tcx > OutOfScopePrecomputer < ' a , ' tcx > {
51+ fn new ( body : & ' a Body < ' tcx > , regioncx : & ' a RegionInferenceContext < ' tcx > ) -> Self {
52+ OutOfScopePrecomputer {
53+ visited : BitSet :: new_empty ( body. basic_blocks ( ) . len ( ) ) ,
54+ visit_stack : vec ! [ ] ,
55+ body,
56+ regioncx,
57+ borrows_out_of_scope_at_location : FxHashMap :: default ( ) ,
8858 }
59+ }
60+ }
8961
90- if !finished_early {
91- // Add successor BBs to the work list, if necessary.
92- let bb_data = & body[ bb] ;
93- assert ! ( hi == bb_data. statements. len( ) ) ;
94- for & succ_bb in bb_data. terminator ( ) . successors ( ) {
95- visited
96- . entry ( succ_bb)
97- . and_modify ( |lo| {
98- // `succ_bb` has been seen before. If it wasn't
99- // fully processed, add its first part to `stack`
100- // for processing.
101- if * lo > 0 {
102- stack. push ( StackEntry {
62+ impl < ' tcx > OutOfScopePrecomputer < ' _ , ' tcx > {
63+ fn precompute_borrows_out_of_scope (
64+ & mut self ,
65+ borrow_index : BorrowIndex ,
66+ borrow_region : RegionVid ,
67+ location : Location ,
68+ ) {
69+ // We visit one BB at a time. The complication is that we may start in the
70+ // middle of the first BB visited (the one containing `location`), in which
71+ // case we may have to later on process the first part of that BB if there
72+ // is a path back to its start.
73+
74+ // For visited BBs, we record the index of the first statement processed.
75+ // (In fully processed BBs this index is 0.) Note also that we add BBs to
76+ // `visited` once they are added to `stack`, before they are actually
77+ // processed, because this avoids the need to look them up again on
78+ // completion.
79+ self . visited . insert ( location. block ) ;
80+
81+ let mut first_lo = location. statement_index ;
82+ let first_hi = self . body [ location. block ] . statements . len ( ) ;
83+
84+ self . visit_stack . push ( StackEntry { bb : location. block , lo : first_lo, hi : first_hi } ) ;
85+
86+ while let Some ( StackEntry { bb, lo, hi } ) = self . visit_stack . pop ( ) {
87+ // If we process the first part of the first basic block (i.e. we encounter that block
88+ // for the second time), we no longer have to visit its successors again.
89+ let mut finished_early = bb == location. block && hi != first_hi;
90+ for i in lo..=hi {
91+ let location = Location { block : bb, statement_index : i } ;
92+ // If region does not contain a point at the location, then add to list and skip
93+ // successor locations.
94+ if !self . regioncx . region_contains ( borrow_region, location) {
95+ debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
96+ self . borrows_out_of_scope_at_location
97+ . entry ( location)
98+ . or_default ( )
99+ . push ( borrow_index) ;
100+ finished_early = true ;
101+ break ;
102+ }
103+ }
104+
105+ if !finished_early {
106+ // Add successor BBs to the work list, if necessary.
107+ let bb_data = & self . body [ bb] ;
108+ debug_assert ! ( hi == bb_data. statements. len( ) ) ;
109+ for & succ_bb in bb_data. terminator ( ) . successors ( ) {
110+ if self . visited . insert ( succ_bb) == false {
111+ if succ_bb == location. block && first_lo > 0 {
112+ // `succ_bb` has been seen before. If it wasn't
113+ // fully processed, add its first part to `stack`
114+ // for processing.
115+ self . visit_stack . push ( StackEntry {
103116 bb : succ_bb,
104117 lo : 0 ,
105- hi : * lo - 1 ,
106- first_part_only : true ,
118+ hi : first_lo - 1 ,
107119 } ) ;
120+
121+ // And update this entry with 0, to represent the
122+ // whole BB being processed.
123+ first_lo = 0 ;
108124 }
109- // And update this entry with 0, to represent the
110- // whole BB being processed.
111- * lo = 0 ;
112- } )
113- . or_insert_with ( || {
125+ } else {
114126 // succ_bb hasn't been seen before. Add it to
115127 // `stack` for processing.
116- stack . push ( StackEntry {
128+ self . visit_stack . push ( StackEntry {
117129 bb : succ_bb,
118130 lo : 0 ,
119- hi : body[ succ_bb] . statements . len ( ) ,
120- first_part_only : false ,
131+ hi : self . body [ succ_bb] . statements . len ( ) ,
121132 } ) ;
122- // Insert 0 for this BB, to represent the whole BB
123- // being processed.
124- 0
125- } ) ;
133+ }
134+ }
126135 }
127136 }
137+
138+ self . visited . clear ( ) ;
128139 }
129140}
130141
131142impl < ' a , ' tcx > Borrows < ' a , ' tcx > {
132143 crate fn new (
133144 tcx : TyCtxt < ' tcx > ,
134145 body : & ' a Body < ' tcx > ,
135- nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
136- borrow_set : & Rc < BorrowSet < ' tcx > > ,
146+ nonlexical_regioncx : & ' a RegionInferenceContext < ' tcx > ,
147+ borrow_set : & ' a BorrowSet < ' tcx > ,
137148 ) -> Self {
138- let mut borrows_out_of_scope_at_location = FxHashMap :: default ( ) ;
149+ let mut prec = OutOfScopePrecomputer :: new ( body , nonlexical_regioncx ) ;
139150 for ( borrow_index, borrow_data) in borrow_set. iter_enumerated ( ) {
140151 let borrow_region = borrow_data. region . to_region_vid ( ) ;
141152 let location = borrow_data. reserve_location ;
142153
143- precompute_borrows_out_of_scope (
144- body,
145- & nonlexical_regioncx,
146- & mut borrows_out_of_scope_at_location,
147- borrow_index,
148- borrow_region,
149- location,
150- ) ;
154+ prec. precompute_borrows_out_of_scope ( borrow_index, borrow_region, location) ;
151155 }
152156
153157 Borrows {
154158 tcx,
155159 body,
156- borrow_set : borrow_set. clone ( ) ,
157- borrows_out_of_scope_at_location,
158- _nonlexical_regioncx : nonlexical_regioncx,
160+ borrow_set,
161+ borrows_out_of_scope_at_location : prec. borrows_out_of_scope_at_location ,
159162 }
160163 }
161164
0 commit comments