@@ -17,10 +17,11 @@ use rustc::hir::def_id::DefId;
17
17
use rustc:: middle:: region;
18
18
use rustc:: mir:: { self , Location , Place , Mir } ;
19
19
use rustc:: ty:: TyCtxt ;
20
- use rustc:: ty:: RegionKind ;
20
+ use rustc:: ty:: { RegionKind , RegionVid } ;
21
21
use rustc:: ty:: RegionKind :: ReScope ;
22
22
23
23
use rustc_data_structures:: bitslice:: BitwiseOperator ;
24
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
24
25
use rustc_data_structures:: indexed_set:: IdxSet ;
25
26
use rustc_data_structures:: indexed_vec:: IndexVec ;
26
27
use rustc_data_structures:: sync:: Lrc ;
@@ -46,9 +47,65 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
46
47
root_scope : Option < region:: Scope > ,
47
48
48
49
borrow_set : Rc < BorrowSet < ' tcx > > ,
50
+ borrows_out_of_scope_at_location : FxHashMap < Location , Vec < BorrowIndex > > ,
49
51
50
52
/// 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
+ }
52
109
}
53
110
54
111
impl < ' a , ' gcx , ' tcx > Borrows < ' a , ' gcx , ' tcx > {
@@ -65,18 +122,28 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
65
122
region:: Scope :: CallSite ( tcx. hir . body ( body_id) . value . hir_id . local_id )
66
123
} ) ;
67
124
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
+
68
135
Borrows {
69
136
tcx : tcx,
70
137
mir : mir,
71
138
borrow_set : borrow_set. clone ( ) ,
139
+ borrows_out_of_scope_at_location,
72
140
scope_tree,
73
141
root_scope,
74
- nonlexical_regioncx,
142
+ _nonlexical_regioncx : nonlexical_regioncx,
75
143
}
76
144
}
77
145
78
146
crate fn borrows ( & self ) -> & IndexVec < BorrowIndex , BorrowData < ' tcx > > { & self . borrow_set . borrows }
79
-
80
147
pub fn scope_tree ( & self ) -> & Lrc < region:: ScopeTree > { & self . scope_tree }
81
148
82
149
pub fn location ( & self , idx : BorrowIndex ) -> & Location {
@@ -89,23 +156,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
89
156
fn kill_loans_out_of_scope_at_location ( & self ,
90
157
sets : & mut BlockSets < BorrowIndex > ,
91
158
location : Location ) {
92
- let regioncx = & self . nonlexical_regioncx ;
93
-
94
159
// 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 .
98
163
//
99
164
// We are careful always to call this function *before* we
100
165
// set up the gen-bits for the statement or
101
166
// termanator. That way, if the effect of the statement or
102
167
// terminator *does* introduce a new loan of the same
103
168
// region, then setting that gen-bit will override any
104
169
// 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) ;
109
173
}
110
174
}
111
175
}
0 commit comments