@@ -22,6 +22,7 @@ use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
22
22
use rustc:: mir:: { Field , Statement , StatementKind , Terminator , TerminatorKind } ;
23
23
use rustc:: mir:: ClosureRegionRequirements ;
24
24
25
+ use rustc_data_structures:: control_flow_graph:: dominators:: Dominators ;
25
26
use rustc_data_structures:: fx:: FxHashSet ;
26
27
use rustc_data_structures:: indexed_set:: IdxSetBuf ;
27
28
use rustc_data_structures:: indexed_vec:: Idx ;
@@ -66,8 +67,6 @@ pub fn provide(providers: &mut Providers) {
66
67
} ;
67
68
}
68
69
69
- struct IsActive ( bool ) ;
70
-
71
70
fn mir_borrowck < ' a , ' tcx > (
72
71
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
73
72
def_id : DefId ,
@@ -234,6 +233,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
234
233
_ => false ,
235
234
} ;
236
235
236
+ let dominators = mir. dominators ( ) ;
237
+
237
238
let mut mbcx = MirBorrowckCtxt {
238
239
tcx : tcx,
239
240
mir : mir,
@@ -250,6 +251,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
250
251
moved_error_reported : FxHashSet ( ) ,
251
252
nonlexical_regioncx : opt_regioncx,
252
253
nonlexical_cause_info : None ,
254
+ dominators,
253
255
} ;
254
256
255
257
let mut state = Flows :: new (
@@ -302,6 +304,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
302
304
/// find out which CFG points are contained in each borrow region.
303
305
nonlexical_regioncx : Option < Rc < RegionInferenceContext < ' tcx > > > ,
304
306
nonlexical_cause_info : Option < RegionCausalInfo > ,
307
+ dominators : Dominators < BasicBlock > ,
305
308
}
306
309
307
310
// Check that:
@@ -856,7 +859,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
856
859
context,
857
860
( sd, place_span. 0 ) ,
858
861
flow_state,
859
- |this, borrow_index, is_active , borrow| match ( rw, borrow. kind ) {
862
+ |this, borrow_index, borrow| match ( rw, borrow. kind ) {
860
863
// Obviously an activation is compatible with its own
861
864
// reservation (or even prior activating uses of same
862
865
// borrow); so don't check if they interfere.
@@ -881,7 +884,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
881
884
882
885
( Read ( kind) , BorrowKind :: Unique ) | ( Read ( kind) , BorrowKind :: Mut { .. } ) => {
883
886
// Reading from mere reservations of mutable-borrows is OK.
884
- if this. allow_two_phase_borrow ( borrow. kind ) && !is_active. 0 {
887
+ if !this. is_active ( borrow, context. loc ) {
888
+ assert ! ( this. allow_two_phase_borrow( borrow. kind) ) ;
885
889
return Control :: Continue ;
886
890
}
887
891
@@ -2234,7 +2238,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2234
2238
flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
2235
2239
mut op : F ,
2236
2240
) where
2237
- F : FnMut ( & mut Self , BorrowIndex , IsActive , & BorrowData < ' tcx > ) -> Control ,
2241
+ F : FnMut ( & mut Self , BorrowIndex , & BorrowData < ' tcx > ) -> Control ,
2238
2242
{
2239
2243
let ( access, place) = access_place;
2240
2244
@@ -2247,21 +2251,86 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2247
2251
// borrows of P, P.a.b, etc.
2248
2252
let mut iter_incoming = flow_state. borrows . iter_incoming ( ) ;
2249
2253
while let Some ( i) = iter_incoming. next ( ) {
2254
+ // TODO -- for now, just skip activations, since
2255
+ // everywhere that activation is set, reservation should
2256
+ // be set
2257
+ if i. is_activation ( ) {
2258
+ continue ;
2259
+ }
2260
+
2250
2261
let borrowed = & data[ i. borrow_index ( ) ] ;
2251
2262
2252
2263
if self . places_conflict ( & borrowed. borrowed_place , place, access) {
2253
2264
debug ! (
2254
2265
"each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}" ,
2255
2266
i, borrowed, place, access
2256
2267
) ;
2257
- let is_active = IsActive ( i. is_activation ( ) ) ;
2258
- let ctrl = op ( self , i. borrow_index ( ) , is_active, borrowed) ;
2268
+ let ctrl = op ( self , i. borrow_index ( ) , borrowed) ;
2259
2269
if ctrl == Control :: Break {
2260
2270
return ;
2261
2271
}
2262
2272
}
2263
2273
}
2264
2274
}
2275
+
2276
+ fn is_active (
2277
+ & self ,
2278
+ borrow_data : & BorrowData < ' tcx > ,
2279
+ location : Location
2280
+ ) -> bool {
2281
+ debug ! ( "is_active(borrow_data={:?}, location={:?})" , borrow_data, location) ;
2282
+
2283
+ // If this is not a 2-phase borrow, it is always active.
2284
+ let activation_location = match borrow_data. activation_location {
2285
+ Some ( v) => v,
2286
+ None => return true ,
2287
+ } ;
2288
+
2289
+ // Otherwise, it is active for every location *except* in between
2290
+ // the reservation and the activation:
2291
+ //
2292
+ // X
2293
+ // /
2294
+ // R <--+ Except for this
2295
+ // / \ | diamond
2296
+ // \ / |
2297
+ // A <------+
2298
+ // |
2299
+ // Z
2300
+ //
2301
+ // Note that we assume that:
2302
+ // - the reservation R dominates the activation A
2303
+ // - the activation A post-dominates the reservation R (ignoring unwinding edges).
2304
+ //
2305
+ // This means that there can't be an edge that leaves A and
2306
+ // comes back into that diamond unless it passes through R.
2307
+ //
2308
+ // Suboptimal: In some cases, this code walks the dominator
2309
+ // tree twice when it only has to be walked once. I am
2310
+ // lazy. -nmatsakis
2311
+
2312
+ // If dominated by the activation A, then it is active. The
2313
+ // activation occurs upon entering the point A, so this is
2314
+ // also true if location == activation_location.
2315
+ if activation_location. dominates ( location, & self . dominators ) {
2316
+ return true ;
2317
+ }
2318
+
2319
+ // The reservation starts *on exiting* the reservation block,
2320
+ // so check if the location is dominated by R.successor. If so,
2321
+ // this point falls in between the reservation and location.
2322
+ let reserve_location = borrow_data. reserve_location . successor_within_block ( ) ;
2323
+ if reserve_location. dominates ( location, & self . dominators ) {
2324
+ false
2325
+ } else {
2326
+ // Otherwise, this point is outside the diamond, so
2327
+ // consider the borrow active. This could happen for
2328
+ // example if the borrow remains active around a loop (in
2329
+ // which case it would be active also for the point R,
2330
+ // which would generate an error).
2331
+ true
2332
+ }
2333
+ }
2265
2334
}
2266
2335
2267
2336
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
0 commit comments