MIR-borrowck: fix diagnostics for closures
This commit is contained in:
parent
45caff88d1
commit
d3e9881ed1
|
@ -1949,7 +1949,7 @@ impl ForeignItem_ {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A free variable referred to in a function.
|
/// A free variable referred to in a function.
|
||||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||||
pub struct Freevar {
|
pub struct Freevar {
|
||||||
/// The variable being accessed free.
|
/// The variable being accessed free.
|
||||||
pub def: Def,
|
pub def: Def,
|
||||||
|
|
|
@ -267,10 +267,10 @@ impl<'tcx> Mir<'tcx> {
|
||||||
let block = &self[location.block];
|
let block = &self[location.block];
|
||||||
let stmts = &block.statements;
|
let stmts = &block.statements;
|
||||||
let idx = location.statement_index;
|
let idx = location.statement_index;
|
||||||
if location.statement_index < stmts.len() {
|
if idx < stmts.len() {
|
||||||
&stmts[idx].source_info
|
&stmts[idx].source_info
|
||||||
} else {
|
} else {
|
||||||
assert!(location.statement_index == stmts.len());
|
assert!(idx == stmts.len());
|
||||||
&block.terminator().source_info
|
&block.terminator().source_info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1169,8 +1169,70 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds the span of arguments of aclosure (within `maybe_closure_span`) and its usage of
|
||||||
|
/// the local assigned at `location`.
|
||||||
|
fn find_closure_span(
|
||||||
|
&self,
|
||||||
|
maybe_closure_span: Span,
|
||||||
|
location: Location,
|
||||||
|
) -> Option<(Span, Span)> {
|
||||||
|
use rustc::hir::ExprClosure;
|
||||||
|
use rustc::mir::AggregateKind;
|
||||||
|
|
||||||
|
let local = if let StatementKind::Assign(Lvalue::Local(local), _) =
|
||||||
|
self.mir[location.block].statements[location.statement_index].kind
|
||||||
|
{
|
||||||
|
local
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
|
||||||
|
if maybe_closure_span != stmt.source_info.span {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref lvs)) = stmt.kind {
|
||||||
|
if let AggregateKind::Closure(def_id, _) = **kind {
|
||||||
|
debug!("find_closure_span: found closure {:?}", lvs);
|
||||||
|
|
||||||
|
return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||||
|
let args_span = if let ExprClosure(_, _, _, span, _) =
|
||||||
|
self.tcx.hir.expect_expr(node_id).node
|
||||||
|
{
|
||||||
|
span
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tcx
|
||||||
|
.with_freevars(node_id, |freevars| {
|
||||||
|
for (v, lv) in freevars.iter().zip(lvs) {
|
||||||
|
if let Operand::Consume(Lvalue::Local(l)) = *lv {
|
||||||
|
if local == l {
|
||||||
|
debug!(
|
||||||
|
"find_closure_span: found captured local {:?}",
|
||||||
|
l
|
||||||
|
);
|
||||||
|
return Some(v.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.map(|var_span| (args_span, var_span))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn report_conflicting_borrow(&mut self,
|
fn report_conflicting_borrow(&mut self,
|
||||||
_context: Context,
|
context: Context,
|
||||||
common_prefix: &Lvalue,
|
common_prefix: &Lvalue,
|
||||||
(lvalue, span): (&Lvalue, Span),
|
(lvalue, span): (&Lvalue, Span),
|
||||||
gen_borrow_kind: BorrowKind,
|
gen_borrow_kind: BorrowKind,
|
||||||
|
@ -1183,38 +1245,60 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
||||||
|
|
||||||
let issued_span = self.retrieve_borrow_span(issued_borrow);
|
let issued_span = self.retrieve_borrow_span(issued_borrow);
|
||||||
|
|
||||||
|
let new_closure_span = self.find_closure_span(span, context.loc);
|
||||||
|
let span = new_closure_span.map(|(args, _)| args).unwrap_or(span);
|
||||||
|
let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location);
|
||||||
|
let issued_span = old_closure_span.map(|(args, _)| args).unwrap_or(issued_span);
|
||||||
|
|
||||||
|
let desc_lvalue = self.describe_lvalue(lvalue);
|
||||||
|
|
||||||
// FIXME: supply non-"" `opt_via` when appropriate
|
// FIXME: supply non-"" `opt_via` when appropriate
|
||||||
let mut err = match (gen_borrow_kind, "immutable", "mutable",
|
let mut err = match (gen_borrow_kind, "immutable", "mutable",
|
||||||
issued_borrow.kind, "immutable", "mutable") {
|
issued_borrow.kind, "immutable", "mutable") {
|
||||||
(BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
|
(BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
|
||||||
(BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) =>
|
(BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) =>
|
||||||
self.tcx.cannot_reborrow_already_borrowed(
|
self.tcx.cannot_reborrow_already_borrowed(
|
||||||
span, &self.describe_lvalue(lvalue), "", lft, issued_span,
|
span, &desc_lvalue, "", lft, issued_span,
|
||||||
"it", rgt, "", end_issued_loan_span, Origin::Mir),
|
"it", rgt, "", end_issued_loan_span, Origin::Mir),
|
||||||
|
|
||||||
(BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) =>
|
(BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) =>
|
||||||
self.tcx.cannot_mutably_borrow_multiply(
|
self.tcx.cannot_mutably_borrow_multiply(
|
||||||
span, &self.describe_lvalue(lvalue), "", issued_span,
|
span, &desc_lvalue, "", issued_span,
|
||||||
"", end_issued_loan_span, Origin::Mir),
|
"", end_issued_loan_span, Origin::Mir),
|
||||||
|
|
||||||
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) =>
|
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) =>
|
||||||
self.tcx.cannot_uniquely_borrow_by_two_closures(
|
self.tcx.cannot_uniquely_borrow_by_two_closures(
|
||||||
span, &self.describe_lvalue(lvalue), issued_span,
|
span, &desc_lvalue, issued_span,
|
||||||
end_issued_loan_span, Origin::Mir),
|
end_issued_loan_span, Origin::Mir),
|
||||||
|
|
||||||
(BorrowKind::Unique, _, _, _, _, _) =>
|
(BorrowKind::Unique, _, _, _, _, _) =>
|
||||||
self.tcx.cannot_uniquely_borrow_by_one_closure(
|
self.tcx.cannot_uniquely_borrow_by_one_closure(
|
||||||
span, &self.describe_lvalue(lvalue), "",
|
span, &desc_lvalue, "",
|
||||||
issued_span, "it", "", end_issued_loan_span, Origin::Mir),
|
issued_span, "it", "", end_issued_loan_span, Origin::Mir),
|
||||||
|
|
||||||
(_, _, _, BorrowKind::Unique, _, _) =>
|
(_, _, _, BorrowKind::Unique, _, _) =>
|
||||||
self.tcx.cannot_reborrow_already_uniquely_borrowed(
|
self.tcx.cannot_reborrow_already_uniquely_borrowed(
|
||||||
span, &self.describe_lvalue(lvalue), "it", "",
|
span, &desc_lvalue, "it", "",
|
||||||
issued_span, "", end_issued_loan_span, Origin::Mir),
|
issued_span, "", end_issued_loan_span, Origin::Mir),
|
||||||
|
|
||||||
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) =>
|
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) =>
|
||||||
unreachable!(),
|
unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some((_, var_span)) = old_closure_span {
|
||||||
|
err.span_label(
|
||||||
|
var_span,
|
||||||
|
format!("previous borrow occurs due to use of `{}` in closure", desc_lvalue),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_, var_span)) = new_closure_span {
|
||||||
|
err.span_label(
|
||||||
|
var_span,
|
||||||
|
format!("borrow occurs due to use of `{}` in closure", desc_lvalue),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Tests that two closures cannot simultaneously have mutable
|
||||||
|
// access to the variable, whether that mutable access be used
|
||||||
|
// for direct assignment or for taking mutable ref. Issue #6801.
|
||||||
|
|
||||||
|
// compile-flags: -Z emit-end-regions -Z borrowck-mir
|
||||||
|
|
||||||
|
#![feature(box_syntax)]
|
||||||
|
|
||||||
|
fn to_fn_mut<F: FnMut()>(f: F) -> F { f }
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
let mut x = 3;
|
||||||
|
let c1 = to_fn_mut(|| x = 4);
|
||||||
|
let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(x: &mut isize) {
|
||||||
|
*x = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
let mut x = 3;
|
||||||
|
let c1 = to_fn_mut(|| set(&mut x));
|
||||||
|
let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() {
|
||||||
|
let mut x = 3;
|
||||||
|
let c1 = to_fn_mut(|| x = 5);
|
||||||
|
let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
}
|
||||||
|
|
||||||
|
fn d() {
|
||||||
|
let mut x = 3;
|
||||||
|
let c1 = to_fn_mut(|| x = 5);
|
||||||
|
let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
|
||||||
|
//~^ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g() {
|
||||||
|
struct Foo {
|
||||||
|
f: Box<isize>
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut x: Box<_> = box Foo { f: box 3 };
|
||||||
|
let c1 = to_fn_mut(|| set(&mut *x.f));
|
||||||
|
let c2 = to_fn_mut(|| set(&mut *x.f));
|
||||||
|
//~^ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:24:24
|
||||||
|
|
|
||||||
|
23 | let c1 = to_fn_mut(|| x = 4);
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
24 | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
25 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:34:24
|
||||||
|
|
|
||||||
|
33 | let c1 = to_fn_mut(|| set(&mut x));
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
34 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
35 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:40:24
|
||||||
|
|
|
||||||
|
39 | let c1 = to_fn_mut(|| x = 5);
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
40 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
41 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:46:24
|
||||||
|
|
|
||||||
|
45 | let c1 = to_fn_mut(|| x = 5);
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
46 | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
47 | //~^ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
48 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:57:24
|
||||||
|
|
|
||||||
|
56 | let c1 = to_fn_mut(|| set(&mut *x.f));
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
57 | let c2 = to_fn_mut(|| set(&mut *x.f));
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
58 | //~^ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
59 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:24:24
|
||||||
|
|
|
||||||
|
23 | let c1 = to_fn_mut(|| x = 4);
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
24 | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
25 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:34:24
|
||||||
|
|
|
||||||
|
33 | let c1 = to_fn_mut(|| set(&mut x));
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
34 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
35 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:40:24
|
||||||
|
|
|
||||||
|
39 | let c1 = to_fn_mut(|| x = 5);
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
40 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
41 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:46:24
|
||||||
|
|
|
||||||
|
45 | let c1 = to_fn_mut(|| x = 5);
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
46 | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
47 | //~^ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
48 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
|
||||||
|
--> $DIR/borrowck-closures-two-mut.rs:57:24
|
||||||
|
|
|
||||||
|
56 | let c1 = to_fn_mut(|| set(&mut *x.f));
|
||||||
|
| -- - previous borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| first mutable borrow occurs here
|
||||||
|
57 | let c2 = to_fn_mut(|| set(&mut *x.f));
|
||||||
|
| ^^ - borrow occurs due to use of `x` in closure
|
||||||
|
| |
|
||||||
|
| second mutable borrow occurs here
|
||||||
|
58 | //~^ ERROR cannot borrow `x` as mutable more than once
|
||||||
|
59 | }
|
||||||
|
| - first borrow ends here
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
Loading…
Reference in New Issue