Issue #46589 - Kill borrows on a local variable whenever we assign over this variable

This commit is contained in:
David Teller 2017-12-15 14:27:06 -06:00
parent eff3de0927
commit fcb10908b0
4 changed files with 45 additions and 39 deletions

View File

@ -338,15 +338,10 @@ fn visit_statement_entry(
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,
);

View File

@ -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;
@ -362,6 +363,14 @@ fn statement_effect_on_borrows(&self,
}
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
@ -404,16 +413,7 @@ fn statement_effect_on_borrows(&self,
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 { .. } |
@ -425,6 +425,21 @@ fn statement_effect_on_borrows(&self,
}
}
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.

View File

@ -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
}

View File

@ -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]
}