Skip to content

Commit d7de4e9

Browse files
author
Cameron Zwarich
committed
Enforce stronger guarantees for mutable borrows
Implement the stronger guarantees for mutable borrows from #12624. This removes the ability to read from a mutably borrowed path for the duration of the borrow, and enforces a unique access path for any mutable borrow, for both reads and writes. This makes mutable borrows work better with concurrent accesses from multiple threads, and it opens the door for allowing moves out of mutably borrowed values, as long as a new value is written before the mutable borrow ends. This also aligns Rust more closely with academic languages based on substructural types and separation logic. The most common situation triggering an error after this change is a call to a function mutably borrowing self with self.field as one of the arguments. The workaround is to bind self.field to a temporary, but the need for these temporaries will hopefully go away after #6268 is fixed. Another situation that triggers an error is using the head expression of a match in an arm that binds a variable with a mutable reference. The use of the head expression needs to be replaced with an expression that reconstructs it from match-bound variables. This fixes #12624. [breaking-change]
1 parent 159e27a commit d7de4e9

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

Diff for: src/librustc/middle/borrowck/check_loans.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,7 @@ impl<'a> CheckLoanCtxt<'a> {
438438
Some(lp) => {
439439
let moved_value_use_kind = match mode {
440440
euv::Copy => {
441-
// FIXME(#12624) -- If we are copying the value,
442-
// we don't care if it's borrowed.
441+
self.check_for_copy_of_frozen_path(id, span, &*lp);
443442
MovedInUse
444443
}
445444
euv::Move(_) => {
@@ -471,6 +470,27 @@ impl<'a> CheckLoanCtxt<'a> {
471470
}
472471
}
473472

473+
fn check_for_copy_of_frozen_path(&self,
474+
id: ast::NodeId,
475+
span: Span,
476+
copy_path: &LoanPath) {
477+
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
478+
UseOk => { }
479+
UseWhileBorrowed(loan_path, loan_span) => {
480+
self.bccx.span_err(
481+
span,
482+
format!("cannot use `{}` because it was mutably borrowed",
483+
self.bccx.loan_path_to_str(copy_path).as_slice())
484+
.as_slice());
485+
self.bccx.span_note(
486+
loan_span,
487+
format!("borrow of `{}` occurs here",
488+
self.bccx.loan_path_to_str(&*loan_path).as_slice())
489+
.as_slice());
490+
}
491+
}
492+
}
493+
474494
fn check_for_move_of_borrowed_path(&self,
475495
id: ast::NodeId,
476496
span: Span,

Diff for: src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn a() {
1212
let mut v = vec!(1, 2, 3);
1313
let vb: &mut [int] = v.as_mut_slice();
1414
match vb {
15-
[_a, ..tail] => {
15+
[_a, ..tail] => { //~ ERROR cannot use `vb[..]` because it was mutably borrowed
1616
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
1717
}
1818
_ => {}

Diff for: src/test/compile-fail/regions-escape-loop-via-vec.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
fn broken() {
1313
let mut x = 3;
1414
let mut _y = vec!(&mut x);
15-
while x < 10 {
16-
let mut z = x;
15+
while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed
16+
let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
1717
_y.push(&mut z); //~ ERROR `z` does not live long enough
1818
x += 1; //~ ERROR cannot assign
1919
}

0 commit comments

Comments
 (0)