@@ -17,10 +17,11 @@ use rustc::hir::def_id::DefId;
1717use rustc:: middle:: region;
1818use rustc:: mir:: { self , Location , Place , Mir } ;
1919use rustc:: ty:: TyCtxt ;
20- use rustc:: ty:: RegionKind ;
20+ use rustc:: ty:: { RegionKind , RegionVid } ;
2121use rustc:: ty:: RegionKind :: ReScope ;
2222
2323use rustc_data_structures:: bitslice:: BitwiseOperator ;
24+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2425use rustc_data_structures:: indexed_set:: IdxSet ;
2526use rustc_data_structures:: indexed_vec:: IndexVec ;
2627use rustc_data_structures:: sync:: Lrc ;
@@ -46,9 +47,65 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
4647 root_scope : Option < region:: Scope > ,
4748
4849 borrow_set : Rc < BorrowSet < ' tcx > > ,
50+ borrows_out_of_scope_at_location : FxHashMap < Location , Vec < BorrowIndex > > ,
4951
5052 /// NLL region inference context with which NLL queries should be resolved
51- nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
53+ _nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
54+ }
55+
56+ fn precompute_borrows_out_of_scope < ' a , ' tcx > (
57+ mir : & ' a Mir < ' tcx > ,
58+ regioncx : & Rc < RegionInferenceContext < ' tcx > > ,
59+ borrows_out_of_scope_at_location : & mut FxHashMap < Location , Vec < BorrowIndex > > ,
60+ borrow_index : BorrowIndex ,
61+ borrow_region : RegionVid ,
62+ location : Location ,
63+ ) {
64+ // Keep track of places we've locations to check and locations that we have checked.
65+ let mut stack = vec ! [ location ] ;
66+ let mut visited = FxHashSet ( ) ;
67+ visited. insert ( location) ;
68+
69+ debug ! (
70+ "borrow {:?} has region {:?} with value {:?}" ,
71+ borrow_index,
72+ borrow_region,
73+ regioncx. region_value_str( borrow_region) ,
74+ ) ;
75+ debug ! ( "borrow {:?} starts at {:?}" , borrow_index, location) ;
76+ while let Some ( location) = stack. pop ( ) {
77+ // If region does not contain a point at the location, then add to list and skip
78+ // successor locations.
79+ if !regioncx. region_contains_point ( borrow_region, location) {
80+ debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
81+ borrows_out_of_scope_at_location
82+ . entry ( location)
83+ . or_insert ( vec ! [ ] )
84+ . push ( borrow_index) ;
85+ continue ;
86+ }
87+
88+ let bb_data = & mir[ location. block ] ;
89+ // If this is the last statement in the block, then add the
90+ // terminator successors next.
91+ if location. statement_index == bb_data. statements . len ( ) {
92+ // Add successors to locations to visit, if not visited before.
93+ if let Some ( ref terminator) = bb_data. terminator {
94+ for block in terminator. successors ( ) {
95+ let loc = block. start_location ( ) ;
96+ if visited. insert ( loc) {
97+ stack. push ( loc) ;
98+ }
99+ }
100+ }
101+ } else {
102+ // Visit next statement in block.
103+ let loc = location. successor_within_block ( ) ;
104+ if visited. insert ( loc) {
105+ stack. push ( loc) ;
106+ }
107+ }
108+ }
52109}
53110
54111impl < ' a , ' gcx , ' tcx > Borrows < ' a , ' gcx , ' tcx > {
@@ -65,18 +122,28 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
65122 region:: Scope :: CallSite ( tcx. hir . body ( body_id) . value . hir_id . local_id )
66123 } ) ;
67124
125+ let mut borrows_out_of_scope_at_location = FxHashMap ( ) ;
126+ for ( borrow_index, borrow_data) in borrow_set. borrows . iter_enumerated ( ) {
127+ let borrow_region = borrow_data. region . to_region_vid ( ) ;
128+ let location = borrow_set. borrows [ borrow_index] . reserve_location ;
129+
130+ precompute_borrows_out_of_scope ( mir, & nonlexical_regioncx,
131+ & mut borrows_out_of_scope_at_location,
132+ borrow_index, borrow_region, location) ;
133+ }
134+
68135 Borrows {
69136 tcx : tcx,
70137 mir : mir,
71138 borrow_set : borrow_set. clone ( ) ,
139+ borrows_out_of_scope_at_location,
72140 scope_tree,
73141 root_scope,
74- nonlexical_regioncx,
142+ _nonlexical_regioncx : nonlexical_regioncx,
75143 }
76144 }
77145
78146 crate fn borrows ( & self ) -> & IndexVec < BorrowIndex , BorrowData < ' tcx > > { & self . borrow_set . borrows }
79-
80147 pub fn scope_tree ( & self ) -> & Lrc < region:: ScopeTree > { & self . scope_tree }
81148
82149 pub fn location ( & self , idx : BorrowIndex ) -> & Location {
@@ -89,23 +156,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
89156 fn kill_loans_out_of_scope_at_location ( & self ,
90157 sets : & mut BlockSets < BorrowIndex > ,
91158 location : Location ) {
92- let regioncx = & self . nonlexical_regioncx ;
93-
94159 // NOTE: The state associated with a given `location`
95- // reflects the dataflow on entry to the statement. If it
96- // does not contain `borrow_region`, then then that means
97- // that the statement at ` location` kills the borrow .
160+ // reflects the dataflow on entry to the statement.
161+ // Iterate over each of the borrows that we've precomputed
162+ // to have went out of scope at this location and kill them .
98163 //
99164 // We are careful always to call this function *before* we
100165 // set up the gen-bits for the statement or
101166 // termanator. That way, if the effect of the statement or
102167 // terminator *does* introduce a new loan of the same
103168 // region, then setting that gen-bit will override any
104169 // potential kill introduced here.
105- for ( borrow_index, borrow_data) in self . borrow_set . borrows . iter_enumerated ( ) {
106- let borrow_region = borrow_data. region . to_region_vid ( ) ;
107- if !regioncx. region_contains_point ( borrow_region, location) {
108- sets. kill ( & borrow_index) ;
170+ if let Some ( indices) = self . borrows_out_of_scope_at_location . get ( & location) {
171+ for index in indices {
172+ sets. kill ( & index) ;
109173 }
110174 }
111175 }
0 commit comments