Skip to content

Commit

Permalink
Issue rust-lang#46589 - Kill borrows on a local variable whenever we …
Browse files Browse the repository at this point in the history
…assign over this variable
  • Loading branch information
Yoric committed Dec 21, 2017
1 parent eff3de0 commit fcb1090
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 39 deletions.
7 changes: 1 addition & 6 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx

match stmt.kind {
StatementKind::Assign(ref lhs, ref rhs) => {
// NOTE: NLL RFC calls for *shallow* write; using Deep
// for short-term compat w/ AST-borrowck. Also, switch
// to shallow requires to dataflow: "if this is an
// assignment `place = <rvalue>`, then any loan for some
// path P of which `place` is a prefix is killed."
self.mutate_place(
ContextKind::AssignLhs.new(location),
(lhs, span),
Deep,
Shallow(None),
JustWrite,
flow_state,
);
Expand Down
35 changes: 25 additions & 10 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::region;
Expand Down Expand Up @@ -362,6 +363,14 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
}

mir::StatementKind::Assign(ref lhs, ref rhs) => {
// Make sure there are no remaining borrows for variables
// that are assigned over.
if let Place::Local(ref local) = *lhs {
// FIXME: Handle the case in which we're assigning over
// a projection (`foo.bar`).
self.kill_borrows_on_local(sets, local, is_activations);
}

// NOTE: if/when the Assign case is revised to inspect
// the assigned_place here, make sure to also
// re-consider the current implementations of the
Expand Down Expand Up @@ -404,16 +413,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
mir::StatementKind::StorageDead(local) => {
// Make sure there are no remaining borrows for locals that
// are gone out of scope.
//
// FIXME: expand this to variables that are assigned over.
if let Some(borrow_indexes) = self.local_map.get(&local) {
sets.kill_all(borrow_indexes.iter()
.map(|b| ReserveOrActivateIndex::reserved(*b)));
if is_activations {
sets.kill_all(borrow_indexes.iter()
.map(|b| ReserveOrActivateIndex::active(*b)));
}
}
self.kill_borrows_on_local(sets, &local, is_activations)
}

mir::StatementKind::InlineAsm { .. } |
Expand All @@ -425,6 +425,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
}
}

fn kill_borrows_on_local(&self,
sets: &mut BlockSets<ReserveOrActivateIndex>,
local: &rustc::mir::Local,
is_activations: bool)
{
if let Some(borrow_indexes) = self.local_map.get(local) {
sets.kill_all(borrow_indexes.iter()
.map(|b| ReserveOrActivateIndex::reserved(*b)));
if is_activations {
sets.kill_all(borrow_indexes.iter()
.map(|b| ReserveOrActivateIndex::active(*b)));
}
}
}

/// Models terminator effect in Reservations and ActiveBorrows
/// flow analyses; `is activations` tells us if we are in the
/// latter case.
Expand Down
9 changes: 5 additions & 4 deletions src/test/compile-fail/issue-25579.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@
// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir

#![feature(rustc_attrs)]

enum Sexpression {
Num(()),
Cons(&'static mut Sexpression)
}

fn causes_ice(mut l: &mut Sexpression) {
fn causes_error_in_ast(mut l: &mut Sexpression) {
loop { match l {
&mut Sexpression::Num(ref mut n) => {},
&mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499]
//[mir]~^ ERROR [E0499]
l = &mut **expr; //[ast]~ ERROR [E0506]
//[mir]~^ ERROR [E0506]
}
}}
}

fn main() {
#[rustc_error]
fn main() { //[mir]~ ERROR compilation successful
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,25 @@

// compile-flags: -Z borrowck=mir -Z nll

#![allow(warnings)]
// This example comes from the NLL RFC.

struct Foo<T> {
t: T,
struct List<T> {
value: T,
next: Option<Box<List<T>>>,
}

impl<T: 'static + Copy> Copy for Foo<T> {}
impl<T: 'static + Copy> Clone for Foo<T> {
fn clone(&self) -> Self {
*self
fn to_refs<T>(list: &mut List<T>) -> Vec<&mut T> {
let mut list = list;
let mut result = vec![];
loop {
result.push(&mut list.value);
if let Some(n) = list.next.as_mut() {
list = n;
} else {
return result;
}
}
}

fn main() {
let mut x = 22;

{
let p = &x;
//~^ ERROR `x` does not live long enough
let w = Foo { t: p };

let v = [w; 22];
}

x += 1;
//~^ ERROR cannot assign to `x` because it is borrowed [E0506]
}

0 comments on commit fcb1090

Please sign in to comment.