Issue #46589 - Kill borrows on a local variable whenever we assign over this variable
This commit is contained in:
parent
eff3de0927
commit
fcb10908b0
@ -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,
|
||||
);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
Loading…
Reference in New Issue
Block a user