@@ -21,7 +21,7 @@ use rustc::ty::{RegionKind, RegionVid};
21
21
use rustc:: ty:: RegionKind :: ReScope ;
22
22
23
23
use rustc_data_structures:: bitslice:: { BitwiseOperator , Word } ;
24
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
24
+ use rustc_data_structures:: fx:: FxHashMap ;
25
25
use rustc_data_structures:: indexed_set:: IdxSet ;
26
26
use rustc_data_structures:: indexed_vec:: IndexVec ;
27
27
use rustc_data_structures:: sync:: Lrc ;
@@ -53,6 +53,13 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
53
53
_nonlexical_regioncx : Rc < RegionInferenceContext < ' tcx > > ,
54
54
}
55
55
56
+ struct StackEntry {
57
+ bb : mir:: BasicBlock ,
58
+ lo : usize ,
59
+ hi : usize ,
60
+ first_part_only : bool
61
+ }
62
+
56
63
fn precompute_borrows_out_of_scope < ' tcx > (
57
64
mir : & Mir < ' tcx > ,
58
65
regioncx : & Rc < RegionInferenceContext < ' tcx > > ,
@@ -61,48 +68,79 @@ fn precompute_borrows_out_of_scope<'tcx>(
61
68
borrow_region : RegionVid ,
62
69
location : Location ,
63
70
) {
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 ( borrow_region, location) {
80
- debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
81
- borrows_out_of_scope_at_location
82
- . entry ( location)
83
- . or_default ( )
84
- . push ( borrow_index) ;
85
- continue ;
71
+ // We visit one BB at a time. The complication is that we may start in the
72
+ // middle of the first BB visited (the one containing `location`), in which
73
+ // case we may have to later on process the first part of that BB if there
74
+ // is a path back to its start.
75
+
76
+ // For visited BBs, we record the index of the first statement processed.
77
+ // (In fully processed BBs this index is 0.) Note also that we add BBs to
78
+ // `visited` once they are added to `stack`, before they are actually
79
+ // processed, because this avoids the need to look them up again on
80
+ // completion.
81
+ let mut visited = FxHashMap ( ) ;
82
+ visited. insert ( location. block , location. statement_index ) ;
83
+
84
+ let mut stack = vec ! [ ] ;
85
+ stack. push ( StackEntry {
86
+ bb : location. block ,
87
+ lo : location. statement_index ,
88
+ hi : mir[ location. block ] . statements . len ( ) ,
89
+ first_part_only : false ,
90
+ } ) ;
91
+
92
+ while let Some ( StackEntry { bb, lo, hi, first_part_only } ) = stack. pop ( ) {
93
+ let mut finished_early = first_part_only;
94
+ for i in lo ..= hi {
95
+ let location = Location { block : bb, statement_index : i } ;
96
+ // If region does not contain a point at the location, then add to list and skip
97
+ // successor locations.
98
+ if !regioncx. region_contains ( borrow_region, location) {
99
+ debug ! ( "borrow {:?} gets killed at {:?}" , borrow_index, location) ;
100
+ borrows_out_of_scope_at_location
101
+ . entry ( location)
102
+ . or_default ( )
103
+ . push ( borrow_index) ;
104
+ finished_early = true ;
105
+ break ;
106
+ }
86
107
}
87
108
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) ;
109
+ if !finished_early {
110
+ // Add successor BBs to the work list, if necessary.
111
+ let bb_data = & mir[ bb] ;
112
+ assert ! ( hi == bb_data. statements. len( ) ) ;
113
+ for & succ_bb in bb_data. terminator . as_ref ( ) . unwrap ( ) . successors ( ) {
114
+ visited. entry ( succ_bb)
115
+ . and_modify ( |lo| {
116
+ // `succ_bb` has been seen before. If it wasn't
117
+ // fully processed, add its first part to `stack`
118
+ // for processing.
119
+ if * lo > 0 {
120
+ stack. push ( StackEntry {
121
+ bb : succ_bb,
122
+ lo : 0 ,
123
+ hi : * lo - 1 ,
124
+ first_part_only : true ,
125
+ } ) ;
126
+ }
127
+ // And update this entry with 0, to represent the
128
+ // whole BB being processed.
129
+ * lo = 0 ;
130
+ } )
131
+ . or_insert_with ( || {
132
+ // succ_bb hasn't been seen before. Add it to
133
+ // `stack` for processing.
134
+ stack. push ( StackEntry {
135
+ bb : succ_bb,
136
+ lo : 0 ,
137
+ hi : mir[ succ_bb] . statements . len ( ) ,
138
+ first_part_only : false ,
139
+ } ) ;
140
+ // Insert 0 for this BB, to represent the whole BB
141
+ // being processed.
142
+ 0
143
+ } ) ;
106
144
}
107
145
}
108
146
}
0 commit comments