diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 9e261d6024891..9201e0e2553ef 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -580,7 +580,19 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> if flow_state.inits.curr_state.contains(&mpi) { // may already be assigned before reaching this statement; // report error. - self.report_illegal_reassignment(context, (lvalue, span)); + // FIXME: Not ideal, it only finds the assignment that lexically comes first + let assigned_lvalue = &move_data.move_paths[mpi].lvalue; + let assignment_stmt = self.mir.basic_blocks().iter().filter_map(|bb| { + bb.statements.iter().find(|stmt| { + if let StatementKind::Assign(ref lv, _) = stmt.kind { + *lv == *assigned_lvalue + } else { + false + } + }) + }).next().unwrap(); + self.report_illegal_reassignment( + context, (lvalue, span), assignment_stmt.source_info.span); } } } @@ -982,11 +994,17 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> err.emit(); } - fn report_illegal_reassignment(&mut self, _context: Context, (lvalue, span): (&Lvalue, Span)) { - let mut err = self.tcx.cannot_reassign_immutable( - span, &self.describe_lvalue(lvalue), Origin::Mir); - // FIXME: add span labels for borrow and assignment points - err.emit(); + fn report_illegal_reassignment(&mut self, + _context: Context, + (lvalue, span): (&Lvalue, Span), + assigned_span: Span) { + self.tcx.cannot_reassign_immutable(span, + &self.describe_lvalue(lvalue), + Origin::Mir) + .span_label(span, "re-assignment of immutable variable") + .span_label(assigned_span, format!("first assignment to `{}`", + self.describe_lvalue(lvalue))) + .emit(); } fn report_assignment_to_static(&mut self, _context: Context, (lvalue, span): (&Lvalue, Span)) { diff --git a/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs b/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs index c219b7c5424e9..3639db5cfc4cd 100644 --- a/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs +++ b/src/test/compile-fail/borrowck/borrowck-match-binding-is-assignment.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: ast mir +//[mir]compile-flags: -Zemit-end-regions -Zborrowck-mir + // Test that immutable pattern bindings cannot be reassigned. #![feature(slice_patterns)] @@ -23,31 +26,41 @@ struct S { pub fn main() { match 1 { x => { - x += 1; //~ ERROR re-assignment of immutable variable `x` + x += 1; //[ast]~ ERROR re-assignment of immutable variable `x` + //[mir]~^ ERROR (Mir) [E0384] + //[mir]~| ERROR (Ast) [E0384] } } match E::Foo(1) { E::Foo(x) => { - x += 1; //~ ERROR re-assignment of immutable variable `x` + x += 1; //[ast]~ ERROR re-assignment of immutable variable `x` + //[mir]~^ ERROR (Mir) [E0384] + //[mir]~| ERROR (Ast) [E0384] } } match (S { bar: 1 }) { S { bar: x } => { - x += 1; //~ ERROR re-assignment of immutable variable `x` + x += 1; //[ast]~ ERROR re-assignment of immutable variable `x` + //[mir]~^ ERROR (Mir) [E0384] + //[mir]~| ERROR (Ast) [E0384] } } match (1,) { (x,) => { - x += 1; //~ ERROR re-assignment of immutable variable `x` + x += 1; //[ast]~ ERROR re-assignment of immutable variable `x` + //[mir]~^ ERROR (Mir) [E0384] + //[mir]~| ERROR (Ast) [E0384] } } match [1,2,3] { [x,_,_] => { - x += 1; //~ ERROR re-assignment of immutable variable `x` + x += 1; //[ast]~ ERROR re-assignment of immutable variable `x` + //[mir]~^ ERROR (Mir) [E0384] + //[mir]~| ERROR (Ast) [E0384] } } }