summaryrefslogtreecommitdiffstats
path: root/src/librustc_mir/borrow_check/mod.rs
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-04-06 20:48:13 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-04-15 07:06:29 -0400
commite1f82aa5908911c6ab5db295d5ea279dfb8fc0e2 (patch)
treec64511ba250cfc6fdd3ec3ededbacc449f74ae9f /src/librustc_mir/borrow_check/mod.rs
parentadd useful debug (diff)
downloadgrust-e1f82aa5908911c6ab5db295d5ea279dfb8fc0e2.tar.gz
grust-e1f82aa5908911c6ab5db295d5ea279dfb8fc0e2.tar.bz2
grust-e1f82aa5908911c6ab5db295d5ea279dfb8fc0e2.tar.xz
determine whether a borrow is active based solely on the location
Diffstat (limited to 'src/librustc_mir/borrow_check/mod.rs')
-rw-r--r--src/librustc_mir/borrow_check/mod.rs83
1 files changed, 76 insertions, 7 deletions
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 7c5f0b97f7..2e64626e2e 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -22,6 +22,7 @@ use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
22use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind}; 22use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
23use rustc::mir::ClosureRegionRequirements; 23use rustc::mir::ClosureRegionRequirements;
24 24
25use rustc_data_structures::control_flow_graph::dominators::Dominators;
25use rustc_data_structures::fx::FxHashSet; 26use rustc_data_structures::fx::FxHashSet;
26use rustc_data_structures::indexed_set::IdxSetBuf; 27use rustc_data_structures::indexed_set::IdxSetBuf;
27use rustc_data_structures::indexed_vec::Idx; 28use rustc_data_structures::indexed_vec::Idx;
@@ -66,8 +67,6 @@ pub fn provide(providers: &mut Providers) {
66 }; 67 };
67} 68}
68 69
69struct IsActive(bool);
70
71fn mir_borrowck<'a, 'tcx>( 70fn mir_borrowck<'a, 'tcx>(
72 tcx: TyCtxt<'a, 'tcx, 'tcx>, 71 tcx: TyCtxt<'a, 'tcx, 'tcx>,
73 def_id: DefId, 72 def_id: DefId,
@@ -234,6 +233,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
234 _ => false, 233 _ => false,
235 }; 234 };
236 235
236 let dominators = mir.dominators();
237
237 let mut mbcx = MirBorrowckCtxt { 238 let mut mbcx = MirBorrowckCtxt {
238 tcx: tcx, 239 tcx: tcx,
239 mir: mir, 240 mir: mir,
@@ -250,6 +251,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
250 moved_error_reported: FxHashSet(), 251 moved_error_reported: FxHashSet(),
251 nonlexical_regioncx: opt_regioncx, 252 nonlexical_regioncx: opt_regioncx,
252 nonlexical_cause_info: None, 253 nonlexical_cause_info: None,
254 dominators,
253 }; 255 };
254 256
255 let mut state = Flows::new( 257 let mut state = Flows::new(
@@ -302,6 +304,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
302 /// find out which CFG points are contained in each borrow region. 304 /// find out which CFG points are contained in each borrow region.
303 nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>, 305 nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
304 nonlexical_cause_info: Option<RegionCausalInfo>, 306 nonlexical_cause_info: Option<RegionCausalInfo>,
307 dominators: Dominators<BasicBlock>,
305} 308}
306 309
307// Check that: 310// Check that:
@@ -856,7 +859,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
856 context, 859 context,
857 (sd, place_span.0), 860 (sd, place_span.0),
858 flow_state, 861 flow_state,
859 |this, borrow_index, is_active, borrow| match (rw, borrow.kind) { 862 |this, borrow_index, borrow| match (rw, borrow.kind) {
860 // Obviously an activation is compatible with its own 863 // Obviously an activation is compatible with its own
861 // reservation (or even prior activating uses of same 864 // reservation (or even prior activating uses of same
862 // borrow); so don't check if they interfere. 865 // borrow); so don't check if they interfere.
@@ -881,7 +884,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
881 884
882 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { 885 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
883 // Reading from mere reservations of mutable-borrows is OK. 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 return Control::Continue; 889 return Control::Continue;
886 } 890 }
887 891
@@ -2234,7 +2238,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2234 flow_state: &Flows<'cx, 'gcx, 'tcx>, 2238 flow_state: &Flows<'cx, 'gcx, 'tcx>,
2235 mut op: F, 2239 mut op: F,
2236 ) where 2240 ) where
2237 F: FnMut(&mut Self, BorrowIndex, IsActive, &BorrowData<'tcx>) -> Control, 2241 F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>) -> Control,
2238 { 2242 {
2239 let (access, place) = access_place; 2243 let (access, place) = access_place;
2240 2244
@@ -2247,6 +2251,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2247 // borrows of P, P.a.b, etc. 2251 // borrows of P, P.a.b, etc.
2248 let mut iter_incoming = flow_state.borrows.iter_incoming(); 2252 let mut iter_incoming = flow_state.borrows.iter_incoming();
2249 while let Some(i) = iter_incoming.next() { 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 let borrowed = &data[i.borrow_index()]; 2261 let borrowed = &data[i.borrow_index()];
2251 2262
2252 if self.places_conflict(&borrowed.borrowed_place, place, access) { 2263 if self.places_conflict(&borrowed.borrowed_place, place, access) {
@@ -2254,14 +2265,72 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2254 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", 2265 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
2255 i, borrowed, place, access 2266 i, borrowed, place, access
2256 ); 2267 );
2257 let is_active = IsActive(i.is_activation()); 2268 let ctrl = op(self, i.borrow_index(), borrowed);
2258 let ctrl = op(self, i.borrow_index(), is_active, borrowed);
2259 if ctrl == Control::Break { 2269 if ctrl == Control::Break {
2260 return; 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
2267impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { 2336impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {