Skip to content

two-phase borrows: support multiple activations in one statement #49678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
assigned_map: FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,

/// Locations which activate borrows.
/// NOTE: A given location may activate more than one borrow in the future
/// when more general two-phase borrow support is introduced, but for now we
/// only need to store one borrow index
activation_map: FxHashMap<Location, BorrowIndex>,
activation_map: FxHashMap<Location, FxHashSet<BorrowIndex>>,

/// Every borrow has a region; this maps each such regions back to
/// its borrow-indexes.
Expand Down Expand Up @@ -174,7 +171,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
location_map: FxHashMap<Location, BorrowIndex>,
assigned_map: FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,
activation_map: FxHashMap<Location, BorrowIndex>,
activation_map: FxHashMap<Location, FxHashSet<BorrowIndex>>,
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
region_span_map: FxHashMap<RegionKind, Span>,
Expand Down Expand Up @@ -211,12 +208,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
let idx = self.idx_vec.push(borrow);
self.location_map.insert(location, idx);

// This assert is a good sanity check until more general 2-phase borrow
// support is introduced. See NOTE on the activation_map field for more
assert!(!self.activation_map.contains_key(&activate_location),
"More than one activation introduced at the same location.");
self.activation_map.insert(activate_location, idx);

insert(&mut self.activation_map, &activate_location, idx);
insert(&mut self.assigned_map, assigned_place, idx);
insert(&mut self.region_map, &region, idx);
if let Some(local) = root_local(borrowed_place) {
Expand Down Expand Up @@ -552,9 +544,11 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
location: Location) {
// Handle activations
match self.activation_map.get(&location) {
Some(&activated) => {
debug!("activating borrow {:?}", activated);
sets.gen(&ReserveOrActivateIndex::active(activated))
Some(activations) => {
for activated in activations {
debug!("activating borrow {:?}", activated);
sets.gen(&ReserveOrActivateIndex::active(*activated))
}
}
None => {}
}
Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/borrowck/two-phase-multi-mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(nll)]

struct Foo {
}

impl Foo {
fn method(&mut self, foo: &mut Foo) {
}
}

fn main() {
let mut foo = Foo { };
foo.method(&mut foo);
//~^ cannot borrow `foo` as mutable more than once at a time
//~^^ cannot borrow `foo` as mutable more than once at a time
}
23 changes: 23 additions & 0 deletions src/test/ui/borrowck/two-phase-multi-mut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0499]: cannot borrow `foo` as mutable more than once at a time
--> $DIR/two-phase-multi-mut.rs:23:16
|
LL | foo.method(&mut foo);
| -----------^^^^^^^^-
| | |
| | second mutable borrow occurs here
| first mutable borrow occurs here
| borrow later used here

error[E0499]: cannot borrow `foo` as mutable more than once at a time
--> $DIR/two-phase-multi-mut.rs:23:5
|
LL | foo.method(&mut foo);
| ^^^^^^^^^^^--------^
| | |
| | first mutable borrow occurs here
| second mutable borrow occurs here
| borrow later used here

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0499`.
35 changes: 35 additions & 0 deletions src/test/ui/borrowck/two-phase-multiple-activations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// revisions: lxl nll
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll

// run-pass

use std::io::Result;

struct Foo {}

pub trait FakeRead {
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>;
}

impl FakeRead for Foo {
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
Ok(4)
}
}

fn main() {
let mut a = Foo {};
let mut v = Vec::new();
a.read_to_end(&mut v);
}