Skip to content

Commit 574dff9

Browse files
authored
Rollup merge of #45927 - sinkuu:mir-borrowck-closure, r=estebank
MIR-borrowck: fix diagnostics for closures Emit notes for captured variables in the same manner as AST borrowck. ``` 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 (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 ``` Fixes #45362.
2 parents 5d9b63c + f99142b commit 574dff9

File tree

5 files changed

+303
-9
lines changed

5 files changed

+303
-9
lines changed

src/librustc/hir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1949,7 +1949,7 @@ impl ForeignItem_ {
19491949
}
19501950

19511951
/// A free variable referred to in a function.
1952-
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
1952+
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
19531953
pub struct Freevar {
19541954
/// The variable being accessed free.
19551955
pub def: Def,

src/librustc/mir/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,10 @@ impl<'tcx> Mir<'tcx> {
267267
let block = &self[location.block];
268268
let stmts = &block.statements;
269269
let idx = location.statement_index;
270-
if location.statement_index < stmts.len() {
270+
if idx < stmts.len() {
271271
&stmts[idx].source_info
272272
} else {
273-
assert!(location.statement_index == stmts.len());
273+
assert!(idx == stmts.len());
274274
&block.terminator().source_info
275275
}
276276
}

src/librustc_mir/borrow_check.rs

+92-6
Original file line numberDiff line numberDiff line change
@@ -1169,8 +1169,72 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
11691169
err.emit();
11701170
}
11711171

1172+
/// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
1173+
/// the local assigned at `location`.
1174+
/// This is done by searching in statements succeeding `location`
1175+
/// and originating from `maybe_closure_span`.
1176+
fn find_closure_span(
1177+
&self,
1178+
maybe_closure_span: Span,
1179+
location: Location,
1180+
) -> Option<(Span, Span)> {
1181+
use rustc::hir::ExprClosure;
1182+
use rustc::mir::AggregateKind;
1183+
1184+
let local = if let StatementKind::Assign(Lvalue::Local(local), _) =
1185+
self.mir[location.block].statements[location.statement_index].kind
1186+
{
1187+
local
1188+
} else {
1189+
return None;
1190+
};
1191+
1192+
for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1193+
if maybe_closure_span != stmt.source_info.span {
1194+
break;
1195+
}
1196+
1197+
if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref lvs)) = stmt.kind {
1198+
if let AggregateKind::Closure(def_id, _) = **kind {
1199+
debug!("find_closure_span: found closure {:?}", lvs);
1200+
1201+
return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
1202+
let args_span = if let ExprClosure(_, _, _, span, _) =
1203+
self.tcx.hir.expect_expr(node_id).node
1204+
{
1205+
span
1206+
} else {
1207+
return None;
1208+
};
1209+
1210+
self.tcx
1211+
.with_freevars(node_id, |freevars| {
1212+
for (v, lv) in freevars.iter().zip(lvs) {
1213+
if let Operand::Consume(Lvalue::Local(l)) = *lv {
1214+
if local == l {
1215+
debug!(
1216+
"find_closure_span: found captured local {:?}",
1217+
l
1218+
);
1219+
return Some(v.span);
1220+
}
1221+
}
1222+
}
1223+
None
1224+
})
1225+
.map(|var_span| (args_span, var_span))
1226+
} else {
1227+
None
1228+
};
1229+
}
1230+
}
1231+
}
1232+
1233+
None
1234+
}
1235+
11721236
fn report_conflicting_borrow(&mut self,
1173-
_context: Context,
1237+
context: Context,
11741238
common_prefix: &Lvalue,
11751239
(lvalue, span): (&Lvalue, Span),
11761240
gen_borrow_kind: BorrowKind,
@@ -1183,38 +1247,60 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
11831247

11841248
let issued_span = self.retrieve_borrow_span(issued_borrow);
11851249

1250+
let new_closure_span = self.find_closure_span(span, context.loc);
1251+
let span = new_closure_span.map(|(args, _)| args).unwrap_or(span);
1252+
let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location);
1253+
let issued_span = old_closure_span.map(|(args, _)| args).unwrap_or(issued_span);
1254+
1255+
let desc_lvalue = self.describe_lvalue(lvalue);
1256+
11861257
// FIXME: supply non-"" `opt_via` when appropriate
11871258
let mut err = match (gen_borrow_kind, "immutable", "mutable",
11881259
issued_borrow.kind, "immutable", "mutable") {
11891260
(BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
11901261
(BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) =>
11911262
self.tcx.cannot_reborrow_already_borrowed(
1192-
span, &self.describe_lvalue(lvalue), "", lft, issued_span,
1263+
span, &desc_lvalue, "", lft, issued_span,
11931264
"it", rgt, "", end_issued_loan_span, Origin::Mir),
11941265

11951266
(BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) =>
11961267
self.tcx.cannot_mutably_borrow_multiply(
1197-
span, &self.describe_lvalue(lvalue), "", issued_span,
1268+
span, &desc_lvalue, "", issued_span,
11981269
"", end_issued_loan_span, Origin::Mir),
11991270

12001271
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) =>
12011272
self.tcx.cannot_uniquely_borrow_by_two_closures(
1202-
span, &self.describe_lvalue(lvalue), issued_span,
1273+
span, &desc_lvalue, issued_span,
12031274
end_issued_loan_span, Origin::Mir),
12041275

12051276
(BorrowKind::Unique, _, _, _, _, _) =>
12061277
self.tcx.cannot_uniquely_borrow_by_one_closure(
1207-
span, &self.describe_lvalue(lvalue), "",
1278+
span, &desc_lvalue, "",
12081279
issued_span, "it", "", end_issued_loan_span, Origin::Mir),
12091280

12101281
(_, _, _, BorrowKind::Unique, _, _) =>
12111282
self.tcx.cannot_reborrow_already_uniquely_borrowed(
1212-
span, &self.describe_lvalue(lvalue), "it", "",
1283+
span, &desc_lvalue, "it", "",
12131284
issued_span, "", end_issued_loan_span, Origin::Mir),
12141285

12151286
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) =>
12161287
unreachable!(),
12171288
};
1289+
1290+
if let Some((_, var_span)) = old_closure_span {
1291+
err.span_label(
1292+
var_span,
1293+
format!("previous borrow occurs due to use of `{}` in closure", desc_lvalue),
1294+
);
1295+
}
1296+
1297+
if let Some((_, var_span)) = new_closure_span {
1298+
err.span_label(
1299+
var_span,
1300+
format!("borrow occurs due to use of `{}` in closure", desc_lvalue),
1301+
);
1302+
}
1303+
12181304
err.emit();
12191305
}
12201306

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Tests that two closures cannot simultaneously have mutable
12+
// access to the variable, whether that mutable access be used
13+
// for direct assignment or for taking mutable ref. Issue #6801.
14+
15+
// compile-flags: -Z emit-end-regions -Z borrowck-mir
16+
17+
#![feature(box_syntax)]
18+
19+
fn to_fn_mut<F: FnMut()>(f: F) -> F { f }
20+
21+
fn a() {
22+
let mut x = 3;
23+
let c1 = to_fn_mut(|| x = 4);
24+
let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
25+
}
26+
27+
fn set(x: &mut isize) {
28+
*x = 4;
29+
}
30+
31+
fn b() {
32+
let mut x = 3;
33+
let c1 = to_fn_mut(|| set(&mut x));
34+
let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
35+
}
36+
37+
fn c() {
38+
let mut x = 3;
39+
let c1 = to_fn_mut(|| x = 5);
40+
let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
41+
}
42+
43+
fn d() {
44+
let mut x = 3;
45+
let c1 = to_fn_mut(|| x = 5);
46+
let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
47+
//~^ ERROR cannot borrow `x` as mutable more than once
48+
}
49+
50+
fn g() {
51+
struct Foo {
52+
f: Box<isize>
53+
}
54+
55+
let mut x: Box<_> = box Foo { f: box 3 };
56+
let c1 = to_fn_mut(|| set(&mut *x.f));
57+
let c2 = to_fn_mut(|| set(&mut *x.f));
58+
//~^ ERROR cannot borrow `x` as mutable more than once
59+
}
60+
61+
fn main() {
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
2+
--> $DIR/borrowck-closures-two-mut.rs:24:24
3+
|
4+
23 | let c1 = to_fn_mut(|| x = 4);
5+
| -- - previous borrow occurs due to use of `x` in closure
6+
| |
7+
| first mutable borrow occurs here
8+
24 | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
9+
| ^^ - borrow occurs due to use of `x` in closure
10+
| |
11+
| second mutable borrow occurs here
12+
25 | }
13+
| - first borrow ends here
14+
15+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
16+
--> $DIR/borrowck-closures-two-mut.rs:34:24
17+
|
18+
33 | let c1 = to_fn_mut(|| set(&mut x));
19+
| -- - previous borrow occurs due to use of `x` in closure
20+
| |
21+
| first mutable borrow occurs here
22+
34 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
23+
| ^^ - borrow occurs due to use of `x` in closure
24+
| |
25+
| second mutable borrow occurs here
26+
35 | }
27+
| - first borrow ends here
28+
29+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
30+
--> $DIR/borrowck-closures-two-mut.rs:40:24
31+
|
32+
39 | let c1 = to_fn_mut(|| x = 5);
33+
| -- - previous borrow occurs due to use of `x` in closure
34+
| |
35+
| first mutable borrow occurs here
36+
40 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
37+
| ^^ - borrow occurs due to use of `x` in closure
38+
| |
39+
| second mutable borrow occurs here
40+
41 | }
41+
| - first borrow ends here
42+
43+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
44+
--> $DIR/borrowck-closures-two-mut.rs:46:24
45+
|
46+
45 | let c1 = to_fn_mut(|| x = 5);
47+
| -- - previous borrow occurs due to use of `x` in closure
48+
| |
49+
| first mutable borrow occurs here
50+
46 | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
51+
| ^^ - borrow occurs due to use of `x` in closure
52+
| |
53+
| second mutable borrow occurs here
54+
47 | //~^ ERROR cannot borrow `x` as mutable more than once
55+
48 | }
56+
| - first borrow ends here
57+
58+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
59+
--> $DIR/borrowck-closures-two-mut.rs:57:24
60+
|
61+
56 | let c1 = to_fn_mut(|| set(&mut *x.f));
62+
| -- - previous borrow occurs due to use of `x` in closure
63+
| |
64+
| first mutable borrow occurs here
65+
57 | let c2 = to_fn_mut(|| set(&mut *x.f));
66+
| ^^ - borrow occurs due to use of `x` in closure
67+
| |
68+
| second mutable borrow occurs here
69+
58 | //~^ ERROR cannot borrow `x` as mutable more than once
70+
59 | }
71+
| - first borrow ends here
72+
73+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
74+
--> $DIR/borrowck-closures-two-mut.rs:24:24
75+
|
76+
23 | let c1 = to_fn_mut(|| x = 4);
77+
| -- - previous borrow occurs due to use of `x` in closure
78+
| |
79+
| first mutable borrow occurs here
80+
24 | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
81+
| ^^ - borrow occurs due to use of `x` in closure
82+
| |
83+
| second mutable borrow occurs here
84+
25 | }
85+
| - first borrow ends here
86+
87+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
88+
--> $DIR/borrowck-closures-two-mut.rs:34:24
89+
|
90+
33 | let c1 = to_fn_mut(|| set(&mut x));
91+
| -- - previous borrow occurs due to use of `x` in closure
92+
| |
93+
| first mutable borrow occurs here
94+
34 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
95+
| ^^ - borrow occurs due to use of `x` in closure
96+
| |
97+
| second mutable borrow occurs here
98+
35 | }
99+
| - first borrow ends here
100+
101+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
102+
--> $DIR/borrowck-closures-two-mut.rs:40:24
103+
|
104+
39 | let c1 = to_fn_mut(|| x = 5);
105+
| -- - previous borrow occurs due to use of `x` in closure
106+
| |
107+
| first mutable borrow occurs here
108+
40 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
109+
| ^^ - borrow occurs due to use of `x` in closure
110+
| |
111+
| second mutable borrow occurs here
112+
41 | }
113+
| - first borrow ends here
114+
115+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
116+
--> $DIR/borrowck-closures-two-mut.rs:46:24
117+
|
118+
45 | let c1 = to_fn_mut(|| x = 5);
119+
| -- - previous borrow occurs due to use of `x` in closure
120+
| |
121+
| first mutable borrow occurs here
122+
46 | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
123+
| ^^ - borrow occurs due to use of `x` in closure
124+
| |
125+
| second mutable borrow occurs here
126+
47 | //~^ ERROR cannot borrow `x` as mutable more than once
127+
48 | }
128+
| - first borrow ends here
129+
130+
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
131+
--> $DIR/borrowck-closures-two-mut.rs:57:24
132+
|
133+
56 | let c1 = to_fn_mut(|| set(&mut *x.f));
134+
| -- - previous borrow occurs due to use of `x` in closure
135+
| |
136+
| first mutable borrow occurs here
137+
57 | let c2 = to_fn_mut(|| set(&mut *x.f));
138+
| ^^ - borrow occurs due to use of `x` in closure
139+
| |
140+
| second mutable borrow occurs here
141+
58 | //~^ ERROR cannot borrow `x` as mutable more than once
142+
59 | }
143+
| - first borrow ends here
144+
145+
error: aborting due to 10 previous errors
146+

0 commit comments

Comments
 (0)