diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 4f0fff58918..2a7a62cd64b 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1021,7 +1021,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> access_lvalue: (ShallowOrDeep, &Lvalue<'tcx>), flow_state: &InProgress<'b, 'gcx, 'tcx>, mut op: F) - where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue) -> Control + where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>, &Lvalue<'tcx>) -> Control { let (access, lvalue) = access_lvalue; @@ -1248,7 +1248,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_use_of_moved_or_uninitialized(&mut self, _context: Context, desired_action: &str, - (lvalue, span): (&Lvalue, Span), + (lvalue, span): (&Lvalue<'tcx>, Span), mpi: MovePathIndex, curr_move_out: &IdxSetBuf) { @@ -1290,8 +1290,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_move_out_while_borrowed(&mut self, _context: Context, - (lvalue, span): (&Lvalue, Span), - borrow: &BorrowData) { + (lvalue, span): (&Lvalue<'tcx>, Span), + borrow: &BorrowData<'tcx>) { self.tcx.cannot_move_when_borrowed(span, &self.describe_lvalue(lvalue), Origin::Mir) @@ -1305,8 +1305,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_use_while_mutably_borrowed(&mut self, _context: Context, - (lvalue, span): (&Lvalue, Span), - borrow : &BorrowData) { + (lvalue, span): (&Lvalue<'tcx>, Span), + borrow : &BorrowData<'tcx>) { let mut err = self.tcx.cannot_use_when_mutably_borrowed( span, &self.describe_lvalue(lvalue), @@ -1382,8 +1382,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_conflicting_borrow(&mut self, context: Context, - common_prefix: &Lvalue, - (lvalue, span): (&Lvalue, Span), + common_prefix: &Lvalue<'tcx>, + (lvalue, span): (&Lvalue<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData, end_issued_loan_span: Option) { @@ -1453,7 +1453,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_illegal_mutation_of_borrowed(&mut self, _: Context, - (lvalue, span): (&Lvalue, Span), + (lvalue, span): (&Lvalue<'tcx>, Span), loan: &BorrowData) { let mut err = self.tcx.cannot_assign_to_borrowed( span, self.retrieve_borrow_span(loan), &self.describe_lvalue(lvalue), Origin::Mir); @@ -1463,7 +1463,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> fn report_illegal_reassignment(&mut self, _context: Context, - (lvalue, span): (&Lvalue, Span), + (lvalue, span): (&Lvalue<'tcx>, Span), assigned_span: Span) { self.tcx.cannot_reassign_immutable(span, &self.describe_lvalue(lvalue), @@ -1474,7 +1474,9 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> .emit(); } - fn report_assignment_to_static(&mut self, _context: Context, (lvalue, span): (&Lvalue, Span)) { + fn report_assignment_to_static(&mut self, + _context: Context, + (lvalue, span): (&Lvalue<'tcx>, Span)) { let mut err = self.tcx.cannot_assign_static( span, &self.describe_lvalue(lvalue), Origin::Mir); err.emit(); @@ -1483,14 +1485,17 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> { // End-user visible description of `lvalue` - fn describe_lvalue(&self, lvalue: &Lvalue) -> String { + fn describe_lvalue(&self, lvalue: &Lvalue<'tcx>) -> String { let mut buf = String::new(); self.append_lvalue_to_string(lvalue, &mut buf, None); buf } // Appends end-user visible description of `lvalue` to `buf`. - fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option) { + fn append_lvalue_to_string(&self, + lvalue: &Lvalue<'tcx>, + buf: &mut String, + autoderef: Option) { match *lvalue { Lvalue::Local(local) => { self.append_local_to_string(local, buf, "_"); @@ -1500,41 +1505,50 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } Lvalue::Projection(ref proj) => { let mut autoderef = autoderef.unwrap_or(false); - let (prefix, suffix, index_operand) = match proj.elem { + + match proj.elem { ProjectionElem::Deref => { if autoderef { - ("", format!(""), None) + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); } else { - ("(*", format!(")"), None) + buf.push_str(&"(*"); + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str(&")"); } }, - ProjectionElem::Downcast(..) => - ("", format!(""), None), // (dont emit downcast info) + ProjectionElem::Downcast(..) => { + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + }, ProjectionElem::Field(field, _ty) => { autoderef = true; - ("", format!(".{}", self.describe_field(&proj.base, field.index())), None) + let is_projection_from_ty_closure = proj.base.ty(self.mir, self.tcx) + .to_ty(self.tcx).is_closure(); + + let field_name = self.describe_field(&proj.base, field.index()); + if is_projection_from_ty_closure { + buf.push_str(&format!("{}", field_name)); + } else { + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str(&format!(".{}", field_name)); + } }, ProjectionElem::Index(index) => { autoderef = true; - ("", format!(""), Some(index)) + + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str("["); + self.append_local_to_string(index, buf, ".."); + buf.push_str("]"); }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; // Since it isn't possible to borrow an element on a particular index and // then use another while the borrow is held, don't output indices details // to avoid confusing the end-user - ("", format!("[..]"), None) + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); + buf.push_str(&"[..]"); }, }; - buf.push_str(prefix); - self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); - if let Some(index) = index_operand { - buf.push_str("["); - self.append_local_to_string(index, buf, ".."); - buf.push_str("]"); - } else { - buf.push_str(&suffix); - } } } } @@ -1549,6 +1563,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } } + // FIXME Instead of passing usize, Field should be passed // End-user visible description of the `field_index`nth field of `base` fn describe_field(&self, base: &Lvalue, field_index: usize) -> String { match *base { @@ -1600,7 +1615,17 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> }, ty::TyArray(ty, _) | ty::TySlice(ty) => { self.describe_field_from_ty(&ty, field_index) - } + }, + ty::TyClosure(closure_def_id, _) => { + // Convert the def-id into a node-id. node-ids are only valid for + // the local code in the current crate, so this returns an `Option` in case + // the closure comes from another crate. But in that case we wouldn't + // be borrowck'ing it, so we can just unwrap: + let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); + let freevar = self.tcx.with_freevars(node_id, |fv| fv[field_index]); + + self.tcx.hir.name(freevar.var_id()).to_string() + } _ => { // Might need a revision when the fields in trait RFC is implemented // (https://github.com/rust-lang/rfcs/pull/1546) diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index cff913b17be..06d61242ec2 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -327,4 +327,28 @@ fn main() { _ => panic!("other case") } } + // Field from upvar + { + let mut x = 0; + || { + let y = &mut x; + &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time + //[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast) + //[mir]~| ERROR cannot borrow `(*x)` as mutable more than once at a time (Mir) + *y = 1; + }; + } + // Field from upvar nested + { + let mut x = 0; + || { + || { + let y = &mut x; + &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time + //[mir]~^ ERROR cannot borrow `**x` as mutable more than once at a time (Ast) + //[mir]~| ERROR cannot borrow `(*x)` as mutable more than once at a time (Mir) + *y = 1; + } + }; + } }