Skip to content

Commit 5144d32

Browse files
committed
Fix printing of upvar in closures
1 parent a6d691b commit 5144d32

File tree

2 files changed

+70
-36
lines changed

2 files changed

+70
-36
lines changed

src/librustc_mir/borrow_check.rs

+46-36
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//! This query borrow-checks the MIR to (further) ensure it is not broken.
1212
1313
use rustc::hir;
14-
use rustc::hir::def::Def;
1514
use rustc::hir::def_id::{DefId};
1615
use rustc::infer::{InferCtxt};
1716
use rustc::ty::{self, TyCtxt, ParamEnv};
@@ -1022,7 +1021,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
10221021
access_lvalue: (ShallowOrDeep, &Lvalue<'tcx>),
10231022
flow_state: &InProgress<'b, 'gcx, 'tcx>,
10241023
mut op: F)
1025-
where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue) -> Control
1024+
where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue<'tcx>) -> Control
10261025
{
10271026
let (access, lvalue) = access_lvalue;
10281027

@@ -1249,7 +1248,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
12491248
fn report_use_of_moved_or_uninitialized(&mut self,
12501249
_context: Context,
12511250
desired_action: &str,
1252-
(lvalue, span): (&Lvalue, Span),
1251+
(lvalue, span): (&Lvalue<'tcx>, Span),
12531252
mpi: MovePathIndex,
12541253
curr_move_out: &IdxSetBuf<MoveOutIndex>) {
12551254

@@ -1291,8 +1290,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
12911290

12921291
fn report_move_out_while_borrowed(&mut self,
12931292
_context: Context,
1294-
(lvalue, span): (&Lvalue, Span),
1295-
borrow: &BorrowData) {
1293+
(lvalue, span): (&Lvalue<'tcx>, Span),
1294+
borrow: &BorrowData<'tcx>) {
12961295
self.tcx.cannot_move_when_borrowed(span,
12971296
&self.describe_lvalue(lvalue),
12981297
Origin::Mir)
@@ -1306,8 +1305,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
13061305

13071306
fn report_use_while_mutably_borrowed(&mut self,
13081307
_context: Context,
1309-
(lvalue, span): (&Lvalue, Span),
1310-
borrow : &BorrowData) {
1308+
(lvalue, span): (&Lvalue<'tcx>, Span),
1309+
borrow : &BorrowData<'tcx>) {
13111310

13121311
let mut err = self.tcx.cannot_use_when_mutably_borrowed(
13131312
span, &self.describe_lvalue(lvalue),
@@ -1383,8 +1382,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
13831382

13841383
fn report_conflicting_borrow(&mut self,
13851384
context: Context,
1386-
common_prefix: &Lvalue,
1387-
(lvalue, span): (&Lvalue, Span),
1385+
common_prefix: &Lvalue<'tcx>,
1386+
(lvalue, span): (&Lvalue<'tcx>, Span),
13881387
gen_borrow_kind: BorrowKind,
13891388
issued_borrow: &BorrowData,
13901389
end_issued_loan_span: Option<Span>) {
@@ -1454,7 +1453,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
14541453

14551454
fn report_illegal_mutation_of_borrowed(&mut self,
14561455
_: Context,
1457-
(lvalue, span): (&Lvalue, Span),
1456+
(lvalue, span): (&Lvalue<'tcx>, Span),
14581457
loan: &BorrowData) {
14591458
let mut err = self.tcx.cannot_assign_to_borrowed(
14601459
span, self.retrieve_borrow_span(loan), &self.describe_lvalue(lvalue), Origin::Mir);
@@ -1464,7 +1463,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
14641463

14651464
fn report_illegal_reassignment(&mut self,
14661465
_context: Context,
1467-
(lvalue, span): (&Lvalue, Span),
1466+
(lvalue, span): (&Lvalue<'tcx>, Span),
14681467
assigned_span: Span) {
14691468
self.tcx.cannot_reassign_immutable(span,
14701469
&self.describe_lvalue(lvalue),
@@ -1475,7 +1474,9 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
14751474
.emit();
14761475
}
14771476

1478-
fn report_assignment_to_static(&mut self, _context: Context, (lvalue, span): (&Lvalue, Span)) {
1477+
fn report_assignment_to_static(&mut self,
1478+
_context: Context,
1479+
(lvalue, span): (&Lvalue<'tcx>, Span)) {
14791480
let mut err = self.tcx.cannot_assign_static(
14801481
span, &self.describe_lvalue(lvalue), Origin::Mir);
14811482
err.emit();
@@ -1484,14 +1485,17 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
14841485

14851486
impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> {
14861487
// End-user visible description of `lvalue`
1487-
fn describe_lvalue(&self, lvalue: &Lvalue) -> String {
1488+
fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> String {
14881489
let mut buf = String::new();
14891490
self.append_lvalue_to_string(lvalue, &mut buf, None);
14901491
buf
14911492
}
14921493

14931494
// Appends end-user visible description of `lvalue` to `buf`.
1494-
fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option<bool>) {
1495+
fn append_lvalue_to_string(&self,
1496+
lvalue: &Lvalue<'tcx>,
1497+
buf: &mut String,
1498+
autoderef: Option<bool>) {
14951499
match *lvalue {
14961500
Lvalue::Local(local) => {
14971501
self.append_local_to_string(local, buf, "_");
@@ -1501,41 +1505,50 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
15011505
}
15021506
Lvalue::Projection(ref proj) => {
15031507
let mut autoderef = autoderef.unwrap_or(false);
1504-
let (prefix, suffix, index_operand) = match proj.elem {
1508+
1509+
match proj.elem {
15051510
ProjectionElem::Deref => {
15061511
if autoderef {
1507-
("", format!(""), None)
1512+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
15081513
} else {
1509-
("(*", format!(")"), None)
1514+
buf.push_str(&"(*");
1515+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
1516+
buf.push_str(&")");
15101517
}
15111518
},
1512-
ProjectionElem::Downcast(..) =>
1513-
("", format!(""), None), // (dont emit downcast info)
1519+
ProjectionElem::Downcast(..) => {
1520+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
1521+
},
15141522
ProjectionElem::Field(field, _ty) => {
15151523
autoderef = true;
1516-
("", format!(".{}", self.describe_field(&proj.base, field.index())), None)
1524+
let is_projection_from_ty_closure = proj.base.ty(self.mir, self.tcx)
1525+
.to_ty(self.tcx).is_closure();
1526+
1527+
let field_name = self.describe_field(&proj.base, field.index());
1528+
if is_projection_from_ty_closure {
1529+
buf.push_str(&format!("{}", field_name));
1530+
} else {
1531+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
1532+
buf.push_str(&format!(".{}", field_name));
1533+
}
15171534
},
15181535
ProjectionElem::Index(index) => {
15191536
autoderef = true;
1520-
("", format!(""), Some(index))
1537+
1538+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
1539+
buf.push_str("[");
1540+
self.append_local_to_string(index, buf, "..");
1541+
buf.push_str("]");
15211542
},
15221543
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
15231544
autoderef = true;
15241545
// Since it isn't possible to borrow an element on a particular index and
15251546
// then use another while the borrow is held, don't output indices details
15261547
// to avoid confusing the end-user
1527-
("", format!("[..]"), None)
1548+
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
1549+
buf.push_str(&"[..]");
15281550
},
15291551
};
1530-
buf.push_str(prefix);
1531-
self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
1532-
if let Some(index) = index_operand {
1533-
buf.push_str("[");
1534-
self.append_local_to_string(index, buf, "..");
1535-
buf.push_str("]");
1536-
} else {
1537-
buf.push_str(&suffix);
1538-
}
15391552
}
15401553
}
15411554
}
@@ -1609,12 +1622,9 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
16091622
// the closure comes from another crate. But in that case we wouldn't
16101623
// be borrowck'ing it, so we can just unwrap:
16111624
let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
1612-
let local_def = self.tcx.with_freevars(node_id, |fv| fv[field_index].def);
1625+
let freevar = self.tcx.with_freevars(node_id, |fv| fv[field_index]);
16131626

1614-
match local_def {
1615-
Def::Local(local_node_id) => self.tcx.hir.name(local_node_id).to_string(),
1616-
_ => unreachable!()
1617-
}
1627+
self.tcx.hir.name(freevar.var_id()).to_string()
16181628
}
16191629
_ => {
16201630
// Might need a revision when the fields in trait RFC is implemented

src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs

+24
Original file line numberDiff line numberDiff line change
@@ -327,4 +327,28 @@ fn main() {
327327
_ => panic!("other case")
328328
}
329329
}
330+
// Field from upvar
331+
{
332+
let mut x = 0;
333+
|| {
334+
let y = &mut x;
335+
&mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
336+
//[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast)
337+
//[mir]~| ERROR cannot borrow `(*x)` as mutable more than once at a time (Mir)
338+
*y = 1;
339+
};
340+
}
341+
// Field from upvar nested
342+
{
343+
let mut x = 0;
344+
|| {
345+
|| {
346+
let y = &mut x;
347+
&mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
348+
//[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast)
349+
//[mir]~| ERROR cannot borrow `(*x)` as mutable more than once at a time (Mir)
350+
*y = 1;
351+
}
352+
};
353+
}
330354
}

0 commit comments

Comments
 (0)