Skip to content

Commit 47d75af

Browse files
Complete re-implementation of 2-phase borrows
See rust-lang#48431 for discussion as to why this was necessary and what we hoped to accomplish. A brief summary: - the first implementation of 2-phase borrows was hard to limit in the way we wanted. That is, it was too good at accepting all 2-phase borrows rather than just autorefs =) - Numerous diagnostic regressions were introduced by 2-phase borrow support which were difficult to fix
1 parent 047bec6 commit 47d75af

File tree

2 files changed

+32
-33
lines changed

2 files changed

+32
-33
lines changed

src/librustc_mir/dataflow/impls/borrows.rs

+32-32
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,10 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
450450

451451
// Perform the DFS.
452452
// `stack` is the stack of locations still under consideration
453+
// `visited` is the set of points we have already visited
453454
// `found_use` is an Option that becomes Some when we find a use
454455
let mut stack = vec![start_location];
456+
let mut visited = FxHashSet();
455457
let mut found_use = None;
456458
while let Some(curr_loc) = stack.pop() {
457459
let block_data = &self.mir.basic_blocks()
@@ -467,6 +469,11 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
467469
continue;
468470
}
469471

472+
if !visited.insert(curr_loc) {
473+
debug!(" Already visited {:?}", curr_loc);
474+
continue;
475+
}
476+
470477
if self.location_contains_use(curr_loc, assigned_place) {
471478
// TODO: Handle this case a little more gracefully. Perhaps collect
472479
// all uses in a vector, and find the point in the CFG that dominates
@@ -529,19 +536,6 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
529536
fn kill_loans_out_of_scope_at_location(&self,
530537
sets: &mut BlockSets<ReserveOrActivateIndex>,
531538
location: Location) {
532-
/*
533-
XXX: bob_twinkles reintroduce this
534-
let block_data = &self.mir[location.block];
535-
if location.statement_index != block_data.statements.len() {
536-
let statement = &block_data.statements[location.statement_index];
537-
if let mir::StatementKind::EndRegion(region_scope) = statement.kind {
538-
for &borrow_index in &self.region_map[&ReScope(region_scope)] {
539-
sets.kill(&ReserveOrActivateIndex::reserved(borrow_index));
540-
sets.kill(&ReserveOrActivateIndex::active(borrow_index));
541-
}
542-
}
543-
}
544-
*/
545539
if let Some(ref regioncx) = self.nonlexical_regioncx {
546540
// NOTE: The state associated with a given `location`
547541
// reflects the dataflow on entry to the statement. If it
@@ -575,6 +569,20 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
575569
.map(|b| ReserveOrActivateIndex::active(*b)));
576570
}
577571
}
572+
573+
/// Performs the activations for a given location
574+
fn perform_activations_at_location(&self,
575+
sets: &mut BlockSets<ReserveOrActivateIndex>,
576+
location: Location) {
577+
// Handle activations
578+
match self.activation_map.get(&location) {
579+
Some(&activated) => {
580+
debug!("activating borrow {:?}", activated);
581+
sets.gen(&ReserveOrActivateIndex::active(activated))
582+
}
583+
None => {}
584+
}
585+
}
578586
}
579587

580588
impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
@@ -605,13 +613,8 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
605613
panic!("could not find statement at location {:?}");
606614
});
607615

608-
// Handle activations
609-
match self.activation_map.get(&location) {
610-
Some(&activated) => {
611-
sets.gen(&ReserveOrActivateIndex::active(activated))
612-
}
613-
None => {}
614-
}
616+
self.perform_activations_at_location(sets, location);
617+
self.kill_loans_out_of_scope_at_location(sets, location);
615618

616619
match stmt.kind {
617620
// EndRegion kills any borrows (reservations and active borrows both)
@@ -643,15 +646,17 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
643646

644647
if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
645648
if is_unsafe_place(self.tcx, self.mir, place) { return; }
649+
let index = self.location_map.get(&location).unwrap_or_else(|| {
650+
panic!("could not find BorrowIndex for location {:?}", location);
651+
});
652+
646653
if let RegionKind::ReEmpty = region {
647-
// If the borrowed value is dead, the region for it
648-
// can be empty. Don't track the borrow in that case.
654+
// If the borrowed value dies before the borrow is used, the region for
655+
// the borrow can be empty. Don't track the borrow in that case.
656+
sets.kill(&ReserveOrActivateIndex::active(*index));
649657
return
650658
}
651659

652-
let index = self.location_map.get(&location).unwrap_or_else(|| {
653-
panic!("could not find BorrowIndex for location {:?}", location);
654-
});
655660
assert!(self.region_map.get(region).unwrap_or_else(|| {
656661
panic!("could not find BorrowIndexs for region {:?}", region);
657662
}).contains(&index));
@@ -714,14 +719,9 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
714719
});
715720

716721
let term = block.terminator();
722+
self.perform_activations_at_location(sets, location);
723+
self.kill_loans_out_of_scope_at_location(sets, location);
717724

718-
// Handle activations
719-
match self.activation_map.get(&location) {
720-
Some(&activated) => {
721-
sets.gen(&ReserveOrActivateIndex::active(activated))
722-
}
723-
None => {}
724-
}
725725

726726
match term.kind {
727727
mir::TerminatorKind::Resume |

src/test/compile-fail/borrowck/two-phase-activation-sharing-interference.rs

-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ fn not_ok() {
5353
*y += 1;
5454
//[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
5555
//[nll_beyond]~^^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
56-
//[nll_target]~^^^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
5756
read(z);
5857
}
5958

0 commit comments

Comments
 (0)