Skip to content

Commit fcb1090

Browse files
committed
Issue #46589 - Kill borrows on a local variable whenever we assign over this variable
1 parent eff3de0 commit fcb1090

File tree

4 files changed

+45
-39
lines changed

4 files changed

+45
-39
lines changed

src/librustc_mir/borrow_check/mod.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -338,15 +338,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
338338

339339
match stmt.kind {
340340
StatementKind::Assign(ref lhs, ref rhs) => {
341-
// NOTE: NLL RFC calls for *shallow* write; using Deep
342-
// for short-term compat w/ AST-borrowck. Also, switch
343-
// to shallow requires to dataflow: "if this is an
344-
// assignment `place = <rvalue>`, then any loan for some
345-
// path P of which `place` is a prefix is killed."
346341
self.mutate_place(
347342
ContextKind::AssignLhs.new(location),
348343
(lhs, span),
349-
Deep,
344+
Shallow(None),
350345
JustWrite,
351346
flow_state,
352347
);

src/librustc_mir/dataflow/impls/borrows.rs

+25-10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use rustc;
1112
use rustc::hir;
1213
use rustc::hir::def_id::DefId;
1314
use rustc::middle::region;
@@ -362,6 +363,14 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
362363
}
363364

364365
mir::StatementKind::Assign(ref lhs, ref rhs) => {
366+
// Make sure there are no remaining borrows for variables
367+
// that are assigned over.
368+
if let Place::Local(ref local) = *lhs {
369+
// FIXME: Handle the case in which we're assigning over
370+
// a projection (`foo.bar`).
371+
self.kill_borrows_on_local(sets, local, is_activations);
372+
}
373+
365374
// NOTE: if/when the Assign case is revised to inspect
366375
// the assigned_place here, make sure to also
367376
// re-consider the current implementations of the
@@ -404,16 +413,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
404413
mir::StatementKind::StorageDead(local) => {
405414
// Make sure there are no remaining borrows for locals that
406415
// are gone out of scope.
407-
//
408-
// FIXME: expand this to variables that are assigned over.
409-
if let Some(borrow_indexes) = self.local_map.get(&local) {
410-
sets.kill_all(borrow_indexes.iter()
411-
.map(|b| ReserveOrActivateIndex::reserved(*b)));
412-
if is_activations {
413-
sets.kill_all(borrow_indexes.iter()
414-
.map(|b| ReserveOrActivateIndex::active(*b)));
415-
}
416-
}
416+
self.kill_borrows_on_local(sets, &local, is_activations)
417417
}
418418

419419
mir::StatementKind::InlineAsm { .. } |
@@ -425,6 +425,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
425425
}
426426
}
427427

428+
fn kill_borrows_on_local(&self,
429+
sets: &mut BlockSets<ReserveOrActivateIndex>,
430+
local: &rustc::mir::Local,
431+
is_activations: bool)
432+
{
433+
if let Some(borrow_indexes) = self.local_map.get(local) {
434+
sets.kill_all(borrow_indexes.iter()
435+
.map(|b| ReserveOrActivateIndex::reserved(*b)));
436+
if is_activations {
437+
sets.kill_all(borrow_indexes.iter()
438+
.map(|b| ReserveOrActivateIndex::active(*b)));
439+
}
440+
}
441+
}
442+
428443
/// Models terminator effect in Reservations and ActiveBorrows
429444
/// flow analyses; `is activations` tells us if we are in the
430445
/// latter case.

src/test/compile-fail/issue-25579.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,22 @@
1111
// revisions: ast mir
1212
//[mir]compile-flags: -Z borrowck=mir
1313

14+
#![feature(rustc_attrs)]
15+
1416
enum Sexpression {
1517
Num(()),
1618
Cons(&'static mut Sexpression)
1719
}
1820

19-
fn causes_ice(mut l: &mut Sexpression) {
21+
fn causes_error_in_ast(mut l: &mut Sexpression) {
2022
loop { match l {
2123
&mut Sexpression::Num(ref mut n) => {},
2224
&mut Sexpression::Cons(ref mut expr) => { //[ast]~ ERROR [E0499]
23-
//[mir]~^ ERROR [E0499]
2425
l = &mut **expr; //[ast]~ ERROR [E0506]
25-
//[mir]~^ ERROR [E0506]
2626
}
2727
}}
2828
}
2929

30-
fn main() {
30+
#[rustc_error]
31+
fn main() { //[mir]~ ERROR compilation successful
3132
}

src/test/compile-fail/nll/where_clauses_in_repeat_rvalue.rs renamed to src/test/run-pass/borrowck/borrowck-nll-iterating-and-updating.rs

+14-19
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,25 @@
1010

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

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

15-
struct Foo<T> {
16-
t: T,
15+
struct List<T> {
16+
value: T,
17+
next: Option<Box<List<T>>>,
1718
}
1819

19-
impl<T: 'static + Copy> Copy for Foo<T> {}
20-
impl<T: 'static + Copy> Clone for Foo<T> {
21-
fn clone(&self) -> Self {
22-
*self
20+
fn to_refs<T>(list: &mut List<T>) -> Vec<&mut T> {
21+
let mut list = list;
22+
let mut result = vec![];
23+
loop {
24+
result.push(&mut list.value);
25+
if let Some(n) = list.next.as_mut() {
26+
list = n;
27+
} else {
28+
return result;
29+
}
2330
}
2431
}
2532

2633
fn main() {
27-
let mut x = 22;
28-
29-
{
30-
let p = &x;
31-
//~^ ERROR `x` does not live long enough
32-
let w = Foo { t: p };
33-
34-
let v = [w; 22];
35-
}
36-
37-
x += 1;
38-
//~^ ERROR cannot assign to `x` because it is borrowed [E0506]
3934
}

0 commit comments

Comments
 (0)