summaryrefslogtreecommitdiffstats
path: root/src/librustc_mir/borrow_check/mod.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-04-17 14:23:57 +0000
committerbors <bors@rust-lang.org>2018-04-17 14:23:57 +0000
commit881a7cd86ef1001bdfa9590878ca24e57794302f (patch)
tree947639046e0b0f2a1ddc5d0ad6d6f4e33040ff44 /src/librustc_mir/borrow_check/mod.rs
parentAuto merge of #49626 - fanzier:chalk-lowering, r=scalexm (diff)
parents/`use_mir`/`use_mir_borrowck`/ (diff)
downloadgrust-881a7cd86ef1001bdfa9590878ca24e57794302f.tar.gz
grust-881a7cd86ef1001bdfa9590878ca24e57794302f.tar.bz2
grust-881a7cd86ef1001bdfa9590878ca24e57794302f.tar.xz
Auto merge of #49836 - nikomatsakis:nll-facts-prep, r=pnkfelix
prep work for using timely dataflow with NLL Two major changes: **Two-phase borrows are overhauled.** We no longer have two bits per borrow. Instead, we track -- for each borrow -- an (optional) "activation point". Then, for each point P where the borrow is in scope, we check where P falls relative to the activation point. If P is between the reservation point and the activation point, then this is the "reservation" phase of the borrow, else the borrow is considered active. This is simpler and means that the dataflow doesn't have to care about 2-phase at all, at last not yet. **We no longer support using the MIR borrow checker without NLL.** It is going to be increasingly untenable to support lexical mode as we go forward, I think, and also of increasingly little value. This also exposed a few bugs in NLL mode due to increased testing. r? @pnkfelix cc @bobtwinkles
Diffstat (limited to 'src/librustc_mir/borrow_check/mod.rs')
-rw-r--r--src/librustc_mir/borrow_check/mod.rs271
1 files changed, 157 insertions, 114 deletions
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 87379651c2..4dd8d245d3 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -22,13 +22,13 @@ 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;
28 29
29use std::rc::Rc; 30use std::rc::Rc;
30 31
31use syntax::ast;
32use syntax_pos::Span; 32use syntax_pos::Span;
33 33
34use dataflow::{do_dataflow, DebugFormatted}; 34use dataflow::{do_dataflow, DebugFormatted};
@@ -37,7 +37,7 @@ use dataflow::MoveDataParamEnv;
37use dataflow::{DataflowResultsConsumer}; 37use dataflow::{DataflowResultsConsumer};
38use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; 38use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
39use dataflow::{EverInitializedPlaces, MovingOutStatements}; 39use dataflow::{EverInitializedPlaces, MovingOutStatements};
40use dataflow::{BorrowData, Borrows, ReserveOrActivateIndex}; 40use dataflow::Borrows;
41use dataflow::indexes::BorrowIndex; 41use dataflow::indexes::BorrowIndex;
42use dataflow::move_paths::{IllegalMoveOriginKind, MoveError}; 42use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
43use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex}; 43use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
@@ -46,12 +46,15 @@ use util::collect_writes::FindAssignments;
46 46
47use std::iter; 47use std::iter;
48 48
49use self::borrow_set::{BorrowSet, BorrowData};
49use self::flows::Flows; 50use self::flows::Flows;
50use self::prefixes::PrefixSet; 51use self::prefixes::PrefixSet;
51use self::MutateMode::{JustWrite, WriteAndRead}; 52use self::MutateMode::{JustWrite, WriteAndRead};
52 53
54crate mod borrow_set;
53mod error_reporting; 55mod error_reporting;
54mod flows; 56mod flows;
57crate mod place_ext;
55mod prefixes; 58mod prefixes;
56 59
57pub(crate) mod nll; 60pub(crate) mod nll;
@@ -70,7 +73,7 @@ fn mir_borrowck<'a, 'tcx>(
70 let input_mir = tcx.mir_validated(def_id); 73 let input_mir = tcx.mir_validated(def_id);
71 debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); 74 debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
72 75
73 if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() { 76 if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() {
74 return None; 77 return None;
75 } 78 }
76 79
@@ -95,19 +98,13 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
95 .as_local_node_id(def_id) 98 .as_local_node_id(def_id)
96 .expect("do_mir_borrowck: non-local DefId"); 99 .expect("do_mir_borrowck: non-local DefId");
97 100
98 // Make our own copy of the MIR. This copy will be modified (in place) to 101 // Replace all regions with fresh inference variables. This
99 // contain non-lexical lifetimes. It will have a lifetime tied 102 // requires first making our own copy of the MIR. This copy will
100 // to the inference context. 103 // be modified (in place) to contain non-lexical lifetimes. It
104 // will have a lifetime tied to the inference context.
101 let mut mir: Mir<'tcx> = input_mir.clone(); 105 let mut mir: Mir<'tcx> = input_mir.clone();
102 let free_regions = if !tcx.nll() { 106 let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir);
103 None 107 let mir = &mir; // no further changes
104 } else {
105 let mir = &mut mir;
106
107 // Replace all regions with fresh inference variables.
108 Some(nll::replace_regions_in_mir(infcx, def_id, param_env, mir))
109 };
110 let mir = &mir;
111 108
112 let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) { 109 let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
113 Ok(move_data) => move_data, 110 Ok(move_data) => move_data,
@@ -189,22 +186,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
189 |bd, i| DebugFormatted::new(&bd.move_data().inits[i]), 186 |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
190 )); 187 ));
191 188
189 let borrow_set = Rc::new(BorrowSet::build(tcx, mir));
190
192 // If we are in non-lexical mode, compute the non-lexical lifetimes. 191 // If we are in non-lexical mode, compute the non-lexical lifetimes.
193 let (opt_regioncx, opt_closure_req) = if let Some(free_regions) = free_regions { 192 let (regioncx, opt_closure_req) = nll::compute_regions(
194 let (regioncx, opt_closure_req) = nll::compute_regions( 193 infcx,
195 infcx, 194 def_id,
196 def_id, 195 free_regions,
197 free_regions, 196 mir,
198 mir, 197 param_env,
199 param_env, 198 &mut flow_inits,
200 &mut flow_inits, 199 &mdpe.move_data,
201 &mdpe.move_data, 200 &borrow_set,
202 ); 201 );
203 (Some(Rc::new(regioncx)), opt_closure_req) 202 let regioncx = Rc::new(regioncx);
204 } else {
205 assert!(!tcx.nll());
206 (None, None)
207 };
208 let flow_inits = flow_inits; // remove mut 203 let flow_inits = flow_inits; // remove mut
209 204
210 let flow_borrows = FlowAtLocation::new(do_dataflow( 205 let flow_borrows = FlowAtLocation::new(do_dataflow(
@@ -213,24 +208,24 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
213 id, 208 id,
214 &attributes, 209 &attributes,
215 &dead_unwinds, 210 &dead_unwinds,
216 Borrows::new(tcx, mir, opt_regioncx.clone(), def_id, body_id), 211 Borrows::new(tcx, mir, regioncx.clone(), def_id, body_id, &borrow_set),
217 |rs, i| { 212 |rs, i| DebugFormatted::new(&rs.location(i)),
218 DebugFormatted::new(&(i.kind(), rs.location(i.borrow_index())))
219 }
220 )); 213 ));
221 214
222 let movable_generator = !match tcx.hir.get(id) { 215 let movable_generator = match tcx.hir.get(id) {
223 hir::map::Node::NodeExpr(&hir::Expr { 216 hir::map::Node::NodeExpr(&hir::Expr {
224 node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)), 217 node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)),
225 .. 218 ..
226 }) => true, 219 }) => false,
227 _ => false, 220 _ => true,
228 }; 221 };
229 222
223 let dominators = mir.dominators();
224
230 let mut mbcx = MirBorrowckCtxt { 225 let mut mbcx = MirBorrowckCtxt {
231 tcx: tcx, 226 tcx: tcx,
232 mir: mir, 227 mir: mir,
233 node_id: id, 228 mir_def_id: def_id,
234 move_data: &mdpe.move_data, 229 move_data: &mdpe.move_data,
235 param_env: param_env, 230 param_env: param_env,
236 movable_generator, 231 movable_generator,
@@ -241,8 +236,10 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
241 access_place_error_reported: FxHashSet(), 236 access_place_error_reported: FxHashSet(),
242 reservation_error_reported: FxHashSet(), 237 reservation_error_reported: FxHashSet(),
243 moved_error_reported: FxHashSet(), 238 moved_error_reported: FxHashSet(),
244 nonlexical_regioncx: opt_regioncx, 239 nonlexical_regioncx: regioncx,
245 nonlexical_cause_info: None, 240 nonlexical_cause_info: None,
241 borrow_set,
242 dominators,
246 }; 243 };
247 244
248 let mut state = Flows::new( 245 let mut state = Flows::new(
@@ -262,7 +259,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
262pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { 259pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
263 tcx: TyCtxt<'cx, 'gcx, 'tcx>, 260 tcx: TyCtxt<'cx, 'gcx, 'tcx>,
264 mir: &'cx Mir<'tcx>, 261 mir: &'cx Mir<'tcx>,
265 node_id: ast::NodeId, 262 mir_def_id: DefId,
266 move_data: &'cx MoveData<'tcx>, 263 move_data: &'cx MoveData<'tcx>,
267 param_env: ParamEnv<'gcx>, 264 param_env: ParamEnv<'gcx>,
268 movable_generator: bool, 265 movable_generator: bool,
@@ -293,8 +290,14 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
293 /// Non-lexical region inference context, if NLL is enabled. This 290 /// Non-lexical region inference context, if NLL is enabled. This
294 /// contains the results from region inference and lets us e.g. 291 /// contains the results from region inference and lets us e.g.
295 /// find out which CFG points are contained in each borrow region. 292 /// find out which CFG points are contained in each borrow region.
296 nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>, 293 nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
297 nonlexical_cause_info: Option<RegionCausalInfo>, 294 nonlexical_cause_info: Option<RegionCausalInfo>,
295
296 /// The set of borrows extracted from the MIR
297 borrow_set: Rc<BorrowSet<'tcx>>,
298
299 /// Dominators for MIR
300 dominators: Dominators<BasicBlock>,
298} 301}
299 302
300// Check that: 303// Check that:
@@ -535,11 +538,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
535 538
536 if self.movable_generator { 539 if self.movable_generator {
537 // Look for any active borrows to locals 540 // Look for any active borrows to locals
538 let domain = flow_state.borrows.operator(); 541 let borrow_set = self.borrow_set.clone();
539 let data = domain.borrows(); 542 flow_state.with_outgoing_borrows(|borrows| {
540 flow_state.borrows.with_iter_outgoing(|borrows| {
541 for i in borrows { 543 for i in borrows {
542 let borrow = &data[i.borrow_index()]; 544 let borrow = &borrow_set[i];
543 self.check_for_local_borrow(borrow, span); 545 self.check_for_local_borrow(borrow, span);
544 } 546 }
545 }); 547 });
@@ -551,13 +553,12 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
551 // Often, the storage will already have been killed by an explicit 553 // Often, the storage will already have been killed by an explicit
552 // StorageDead, but we don't always emit those (notably on unwind paths), 554 // StorageDead, but we don't always emit those (notably on unwind paths),
553 // so this "extra check" serves as a kind of backup. 555 // so this "extra check" serves as a kind of backup.
554 let domain = flow_state.borrows.operator(); 556 let borrow_set = self.borrow_set.clone();
555 let data = domain.borrows(); 557 flow_state.with_outgoing_borrows(|borrows| {
556 flow_state.borrows.with_iter_outgoing(|borrows| {
557 for i in borrows { 558 for i in borrows {
558 let borrow = &data[i.borrow_index()]; 559 let borrow = &borrow_set[i];
559 let context = ContextKind::StorageDead.new(loc); 560 let context = ContextKind::StorageDead.new(loc);
560 self.check_for_invalidation_at_exit(context, borrow, span, flow_state); 561 self.check_for_invalidation_at_exit(context, borrow, span);
561 } 562 }
562 }); 563 });
563 } 564 }
@@ -836,27 +837,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
836 rw: ReadOrWrite, 837 rw: ReadOrWrite,
837 flow_state: &Flows<'cx, 'gcx, 'tcx>, 838 flow_state: &Flows<'cx, 'gcx, 'tcx>,
838 ) -> bool { 839 ) -> bool {
840 debug!(
841 "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
842 context,
843 place_span,
844 sd,
845 rw,
846 );
847
839 let mut error_reported = false; 848 let mut error_reported = false;
840 self.each_borrow_involving_path( 849 self.each_borrow_involving_path(
841 context, 850 context,
842 (sd, place_span.0), 851 (sd, place_span.0),
843 flow_state, 852 flow_state,
844 |this, index, borrow| match (rw, borrow.kind) { 853 |this, borrow_index, borrow| match (rw, borrow.kind) {
845 // Obviously an activation is compatible with its own 854 // Obviously an activation is compatible with its own
846 // reservation (or even prior activating uses of same 855 // reservation (or even prior activating uses of same
847 // borrow); so don't check if they interfere. 856 // borrow); so don't check if they interfere.
848 // 857 //
849 // NOTE: *reservations* do conflict with themselves; 858 // NOTE: *reservations* do conflict with themselves;
850 // thus aren't injecting unsoundenss w/ this check.) 859 // thus aren't injecting unsoundenss w/ this check.)
851 (Activation(_, activating), _) if activating == index.borrow_index() => { 860 (Activation(_, activating), _) if activating == borrow_index => {
852 debug!( 861 debug!(
853 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \ 862 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
854 skipping {:?} b/c activation of same borrow_index: {:?}", 863 skipping {:?} b/c activation of same borrow_index",
855 place_span, 864 place_span,
856 sd, 865 sd,
857 rw, 866 rw,
858 (index, borrow), 867 (borrow_index, borrow),
859 index.borrow_index()
860 ); 868 );
861 Control::Continue 869 Control::Continue
862 } 870 }
@@ -867,7 +875,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
867 875
868 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { 876 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
869 // Reading from mere reservations of mutable-borrows is OK. 877 // Reading from mere reservations of mutable-borrows is OK.
870 if this.allow_two_phase_borrow(borrow.kind) && index.is_reservation() { 878 if !this.is_active(borrow, context.loc) {
879 assert!(this.allow_two_phase_borrow(borrow.kind));
871 return Control::Continue; 880 return Control::Continue;
872 } 881 }
873 882
@@ -877,17 +886,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
877 this.report_use_while_mutably_borrowed(context, place_span, borrow) 886 this.report_use_while_mutably_borrowed(context, place_span, borrow)
878 } 887 }
879 ReadKind::Borrow(bk) => { 888 ReadKind::Borrow(bk) => {
880 let end_issued_loan_span = flow_state
881 .borrows
882 .operator()
883 .opt_region_end_span(&borrow.region);
884 error_reported = true; 889 error_reported = true;
885 this.report_conflicting_borrow( 890 this.report_conflicting_borrow(
886 context, 891 context,
887 place_span, 892 place_span,
888 bk, 893 bk,
889 &borrow, 894 &borrow,
890 end_issued_loan_span,
891 ) 895 )
892 } 896 }
893 } 897 }
@@ -919,18 +923,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
919 923
920 match kind { 924 match kind {
921 WriteKind::MutableBorrow(bk) => { 925 WriteKind::MutableBorrow(bk) => {
922 let end_issued_loan_span = flow_state
923 .borrows
924 .operator()
925 .opt_region_end_span(&borrow.region);
926
927 error_reported = true; 926 error_reported = true;
928 this.report_conflicting_borrow( 927 this.report_conflicting_borrow(
929 context, 928 context,
930 place_span, 929 place_span,
931 bk, 930 bk,
932 &borrow, 931 &borrow,
933 end_issued_loan_span,
934 ) 932 )
935 } 933 }
936 WriteKind::StorageDeadOrDrop => { 934 WriteKind::StorageDeadOrDrop => {
@@ -939,7 +937,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
939 context, 937 context,
940 borrow, 938 borrow,
941 place_span.1, 939 place_span.1,
942 flow_state.borrows.operator(),
943 ); 940 );
944 } 941 }
945 WriteKind::Mutate => { 942 WriteKind::Mutate => {
@@ -1141,7 +1138,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1141 context: Context, 1138 context: Context,
1142 borrow: &BorrowData<'tcx>, 1139 borrow: &BorrowData<'tcx>,
1143 span: Span, 1140 span: Span,
1144 flow_state: &Flows<'cx, 'gcx, 'tcx>,
1145 ) { 1141 ) {
1146 debug!("check_for_invalidation_at_exit({:?})", borrow); 1142 debug!("check_for_invalidation_at_exit({:?})", borrow);
1147 let place = &borrow.borrowed_place; 1143 let place = &borrow.borrowed_place;
@@ -1194,7 +1190,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1194 context, 1190 context,
1195 borrow, 1191 borrow,
1196 span, 1192 span,
1197 flow_state.borrows.operator(),
1198 ) 1193 )
1199 } 1194 }
1200 } 1195 }
@@ -1249,36 +1244,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1249 // Two-phase borrow support: For each activation that is newly 1244 // Two-phase borrow support: For each activation that is newly
1250 // generated at this statement, check if it interferes with 1245 // generated at this statement, check if it interferes with
1251 // another borrow. 1246 // another borrow.
1252 let domain = flow_state.borrows.operator(); 1247 let borrow_set = self.borrow_set.clone();
1253 let data = domain.borrows(); 1248 for &borrow_index in borrow_set.activations_at_location(location) {
1254 flow_state.borrows.each_gen_bit(|gen| { 1249 let borrow = &borrow_set[borrow_index];
1255 if gen.is_activation() { 1250
1256 let borrow_index = gen.borrow_index(); 1251 // only mutable borrows should be 2-phase
1257 let borrow = &data[borrow_index]; 1252 assert!(match borrow.kind {
1258 // currently the flow analysis registers 1253 BorrowKind::Shared => false,
1259 // activations for both mutable and immutable 1254 BorrowKind::Unique | BorrowKind::Mut { .. } => true,
1260 // borrows. So make sure we are talking about a 1255 });
1261 // mutable borrow before we check it. 1256
1262 match borrow.kind { 1257 self.access_place(
1263 BorrowKind::Shared => return, 1258 ContextKind::Activation.new(location),
1264 BorrowKind::Unique | BorrowKind::Mut { .. } => {} 1259 (&borrow.borrowed_place, span),
1265 } 1260 (
1266 1261 Deep,
1267 self.access_place( 1262 Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index),
1268 ContextKind::Activation.new(location), 1263 ),
1269 (&borrow.borrowed_place, span), 1264 LocalMutationIsAllowed::No,
1270 ( 1265 flow_state,
1271 Deep, 1266 );
1272 Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index), 1267 // We do not need to call `check_if_path_or_subpath_is_moved`
1273 ), 1268 // again, as we already called it when we made the
1274 LocalMutationIsAllowed::No, 1269 // initial reservation.
1275 flow_state, 1270 }
1276 );
1277 // We do not need to call `check_if_path_or_subpath_is_moved`
1278 // again, as we already called it when we made the
1279 // initial reservation.
1280 }
1281 });
1282 } 1271 }
1283} 1272}
1284 1273
@@ -2217,18 +2206,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2217 unreachable!("iter::repeat returned None") 2206 unreachable!("iter::repeat returned None")
2218 } 2207 }
2219 2208
2220 /// This function iterates over all of the current borrows 2209 /// This function iterates over all of the in-scope borrows that
2221 /// (represented by 1-bits in `flow_state.borrows`) that conflict 2210 /// conflict with an access to a place, invoking the `op` callback
2222 /// with an access to a place, invoking the `op` callback for each 2211 /// for each one.
2223 /// one.
2224 /// 2212 ///
2225 /// "Current borrow" here means a borrow that reaches the point in 2213 /// "Current borrow" here means a borrow that reaches the point in
2226 /// the control-flow where the access occurs. 2214 /// the control-flow where the access occurs.
2227 /// 2215 ///
2228 /// The borrow's phase is represented by the ReserveOrActivateIndex 2216 /// The borrow's phase is represented by the IsActive parameter
2229 /// passed to the callback: one can call `is_reservation()` and 2217 /// passed to the callback.
2230 /// `is_activation()` to determine what phase the borrow is
2231 /// currently in, when such distinction matters.
2232 fn each_borrow_involving_path<F>( 2218 fn each_borrow_involving_path<F>(
2233 &mut self, 2219 &mut self,
2234 _context: Context, 2220 _context: Context,
@@ -2236,20 +2222,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2236 flow_state: &Flows<'cx, 'gcx, 'tcx>, 2222 flow_state: &Flows<'cx, 'gcx, 'tcx>,
2237 mut op: F, 2223 mut op: F,
2238 ) where 2224 ) where
2239 F: FnMut(&mut Self, ReserveOrActivateIndex, &BorrowData<'tcx>) -> Control, 2225 F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>) -> Control,
2240 { 2226 {
2241 let (access, place) = access_place; 2227 let (access, place) = access_place;
2242 2228
2243 // FIXME: analogous code in check_loans first maps `place` to 2229 // FIXME: analogous code in check_loans first maps `place` to
2244 // its base_path. 2230 // its base_path.
2245 2231
2246 let data = flow_state.borrows.operator().borrows();
2247
2248 // check for loan restricting path P being used. Accounts for 2232 // check for loan restricting path P being used. Accounts for
2249 // borrows of P, P.a.b, etc. 2233 // borrows of P, P.a.b, etc.
2250 let mut iter_incoming = flow_state.borrows.iter_incoming(); 2234 let borrow_set = self.borrow_set.clone();
2251 while let Some(i) = iter_incoming.next() { 2235 for i in flow_state.borrows_in_scope() {
2252 let borrowed = &data[i.borrow_index()]; 2236 let borrowed = &borrow_set[i];
2253 2237
2254 if self.places_conflict(&borrowed.borrowed_place, place, access) { 2238 if self.places_conflict(&borrowed.borrowed_place, place, access) {
2255 debug!( 2239 debug!(
@@ -2263,6 +2247,65 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2263 } 2247 }
2264 } 2248 }
2265 } 2249 }
2250
2251 fn is_active(
2252 &self,
2253 borrow_data: &BorrowData<'tcx>,
2254 location: Location
2255 ) -> bool {
2256 debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);
2257
2258 // If this is not a 2-phase borrow, it is always active.
2259 let activation_location = match borrow_data.activation_location {
2260 Some(v) => v,
2261 None => return true,
2262 };
2263
2264 // Otherwise, it is active for every location *except* in between
2265 // the reservation and the activation:
2266 //
2267 // X
2268 // /
2269 // R <--+ Except for this
2270 // / \ | diamond
2271 // \ / |
2272 // A <------+
2273 // |
2274 // Z
2275 //
2276 // Note that we assume that:
2277 // - the reservation R dominates the activation A
2278 // - the activation A post-dominates the reservation R (ignoring unwinding edges).
2279 //
2280 // This means that there can't be an edge that leaves A and
2281 // comes back into that diamond unless it passes through R.
2282 //
2283 // Suboptimal: In some cases, this code walks the dominator
2284 // tree twice when it only has to be walked once. I am
2285 // lazy. -nmatsakis
2286
2287 // If dominated by the activation A, then it is active. The
2288 // activation occurs upon entering the point A, so this is
2289 // also true if location == activation_location.
2290 if activation_location.dominates(location, &self.dominators) {
2291 return true;
2292 }
2293
2294 // The reservation starts *on exiting* the reservation block,
2295 // so check if the location is dominated by R.successor. If so,
2296 // this point falls in between the reservation and location.
2297 let reserve_location = borrow_data.reserve_location.successor_within_block();
2298 if reserve_location.dominates(location, &self.dominators) {
2299 false
2300 } else {
2301 // Otherwise, this point is outside the diamond, so
2302 // consider the borrow active. This could happen for
2303 // example if the borrow remains active around a loop (in
2304 // which case it would be active also for the point R,
2305 // which would generate an error).
2306 true
2307 }
2308 }
2266} 2309}
2267 2310
2268impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { 2311impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {