diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 14b6e31913250..14e6f59782651 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -14,7 +14,7 @@ use rustc::hir::def_id::{DefId}; use rustc::infer::{InferCtxt}; use rustc::ty::{self, TyCtxt, ParamEnv}; use rustc::ty::maps::Providers; -use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue}; +use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local}; use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind}; use rustc::mir::transform::{MirSource}; @@ -1053,49 +1053,52 @@ 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 { let mut buf = String::new(); - self.append_lvalue_to_string(lvalue, &mut buf); + 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) { + fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option) { match *lvalue { Lvalue::Local(local) => { - let local = &self.mir.local_decls[local]; - match local.name { - Some(name) => buf.push_str(&format!("{}", name)), - None => buf.push_str("_"), - } + self.append_local_to_string(local, buf, "_"); } Lvalue::Static(ref static_) => { buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id))); } Lvalue::Projection(ref proj) => { + let mut autoderef = autoderef.unwrap_or(false); let (prefix, suffix, index_operand) = match proj.elem { - ProjectionElem::Deref => - ("(*", format!(")"), None), + ProjectionElem::Deref => { + if autoderef { + ("", format!(""), None) + } else { + ("(*", format!(")"), None) + } + }, ProjectionElem::Downcast(..) => ("", format!(""), None), // (dont emit downcast info) - ProjectionElem::Field(field, _ty) => - ("", format!(".{}", field.index()), None), // FIXME: report name of field - ProjectionElem::Index(index) => - ("", format!(""), Some(index)), - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => - ("", format!("[{} of {}]", offset, min_length), None), - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => - ("", format!("[-{} of {}]", offset, min_length), None), - ProjectionElem::Subslice { from, to: 0 } => - ("", format!("[{}:]", from), None), - ProjectionElem::Subslice { from: 0, to } => - ("", format!("[:-{}]", to), None), - ProjectionElem::Subslice { from, to } => - ("", format!("[{}:-{}]", from, to), None), + ProjectionElem::Field(field, _ty) => { + autoderef = true; + ("", format!(".{}", self.describe_field(&proj.base, field.index())), None) + }, + ProjectionElem::Index(index) => { + autoderef = true; + ("", format!(""), Some(index)) + }, + 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) + }, }; buf.push_str(prefix); - self.append_lvalue_to_string(&proj.base, buf); + self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); if let Some(index) = index_operand { buf.push_str("["); - self.append_lvalue_to_string(&Lvalue::Local(index), buf); + self.append_local_to_string(index, buf, ".."); buf.push_str("]"); } else { buf.push_str(&suffix); @@ -1104,6 +1107,77 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } } + // Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have + // a name, then `none_string` is appended instead + fn append_local_to_string(&self, local_index: Local, buf: &mut String, none_string: &str) { + let local = &self.mir.local_decls[local_index]; + match local.name { + Some(name) => buf.push_str(&format!("{}", name)), + None => buf.push_str(none_string) + } + } + + // End-user visible description of the `field_index`nth field of `base` + fn describe_field(&self, base: &Lvalue, field_index: usize) -> String { + match *base { + Lvalue::Local(local) => { + let local = &self.mir.local_decls[local]; + self.describe_field_from_ty(&local.ty, field_index) + }, + Lvalue::Static(ref static_) => { + self.describe_field_from_ty(&static_.ty, field_index) + }, + Lvalue::Projection(ref proj) => { + match proj.elem { + ProjectionElem::Deref => + self.describe_field(&proj.base, field_index), + ProjectionElem::Downcast(def, variant_index) => + format!("{}", def.variants[variant_index].fields[field_index].name), + ProjectionElem::Field(_, field_type) => + self.describe_field_from_ty(&field_type, field_index), + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => + format!("{}", self.describe_field(&proj.base, field_index)), + } + } + } + } + + // End-user visible description of the `field_index`nth field of `ty` + fn describe_field_from_ty(&self, ty: &ty::Ty, field_index: usize) -> String { + if ty.is_box() { + // If the type is a box, the field is described from the boxed type + self.describe_field_from_ty(&ty.boxed_ty(), field_index) + } + else { + match ty.sty { + ty::TyAdt(def, _) => { + if def.is_enum() { + format!("{}", field_index) + } + else { + format!("{}", def.struct_variant().fields[field_index].name) + } + }, + ty::TyTuple(_, _) => { + format!("{}", field_index) + }, + ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => { + self.describe_field_from_ty(&tnm.ty, field_index) + }, + ty::TyArray(ty, _) | ty::TySlice(ty) => { + self.describe_field_from_ty(&ty, field_index) + } + _ => { + // Might need a revision when the fields in trait RFC is implemented + // (https://github.com/rust-lang/rfcs/pull/1546) + bug!("End-user description not implemented for field access on `{:?}`", ty.sty); + } + } + } + } + // Retrieve span of given borrow from the current MIR representation fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span { self.mir.basic_blocks()[borrow.location.block] diff --git a/src/test/compile-fail/borrowck/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck/borrowck-assign-comp.rs index e63de3a3bed79..548436c3ed870 100644 --- a/src/test/compile-fail/borrowck/borrowck-assign-comp.rs +++ b/src/test/compile-fail/borrowck/borrowck-assign-comp.rs @@ -22,7 +22,7 @@ fn a() { // immutable. Otherwise the type of &_q.x (&isize) would be wrong. p.x = 5; //[ast]~ ERROR cannot assign to `p.x` //[mir]~^ ERROR cannot assign to `p.x` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `p.0` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `p.x` because it is borrowed (Mir) q.x; } @@ -47,7 +47,7 @@ fn d() { let q = &p.y; p.y = 5; //[ast]~ ERROR cannot assign to `p.y` //[mir]~^ ERROR cannot assign to `p.y` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `p.1` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `p.y` because it is borrowed (Mir) *q; } diff --git a/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs index 6c003ec2d48b3..0b6b9bf7d484d 100644 --- a/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs @@ -82,7 +82,7 @@ fn g() { let c1 = || get(&*x.f); *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f` //[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `(*(*x).0)` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `(*x.f)` because it is borrowed (Mir) } fn h() { diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs new file mode 100644 index 0000000000000..cff913b17bedd --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -0,0 +1,330 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +#![feature(slice_patterns)] +#![feature(advanced_slice_patterns)] + +pub struct Foo { + x: u32 +} + +pub struct Bar(u32); + +pub enum Baz { + X(u32) +} + +union U { + a: u8, + b: u64, +} + +impl Foo { + fn x(&mut self) -> &mut u32 { &mut self.x } +} + +impl Bar { + fn x(&mut self) -> &mut u32 { &mut self.0 } +} + +impl Baz { + fn x(&mut self) -> &mut u32 { + match *self { + Baz::X(ref mut value) => value + } + } +} + +static mut sfoo : Foo = Foo{x: 23 }; +static mut sbar : Bar = Bar(23); +static mut stuple : (i32, i32) = (24, 25); +static mut senum : Baz = Baz::X(26); +static mut sunion : U = U { a: 0 }; + +fn main() { + // Local and field from struct + { + let mut f = Foo { x: 22 }; + let _x = f.x(); + f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed + //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `f.x` because it was mutably borrowed (Mir) + } + // Local and field from tuple-struct + { + let mut g = Bar(22); + let _0 = g.x(); + g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `g.0` because it was mutably borrowed (Mir) + } + // Local and field from tuple + { + let mut h = (22, 23); + let _0 = &mut h.0; + h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `h.0` because it was mutably borrowed (Mir) + } + // Local and field from enum + { + let mut e = Baz::X(2); + let _e0 = e.x(); + match e { + Baz::X(value) => value + //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `e.0` because it was mutably borrowed (Mir) + }; + } + // Local and field from union + unsafe { + let mut u = U { b: 0 }; + let _ra = &mut u.a; + u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed + //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) + } + // Static and field from struct + unsafe { + let _x = sfoo.x(); + sfoo.x; //[mir]~ ERROR cannot use `sfoo.x` because it was mutably borrowed (Mir) + } + // Static and field from tuple-struct + unsafe { + let _0 = sbar.x(); + sbar.0; //[mir]~ ERROR cannot use `sbar.0` because it was mutably borrowed (Mir) + } + // Static and field from tuple + unsafe { + let _0 = &mut stuple.0; + stuple.0; //[mir]~ ERROR cannot use `stuple.0` because it was mutably borrowed (Mir) + } + // Static and field from enum + unsafe { + let _e0 = senum.x(); + match senum { + Baz::X(value) => value + //[mir]~^ ERROR cannot use `senum.0` because it was mutably borrowed (Mir) + }; + } + // Static and field from union + unsafe { + let _ra = &mut sunion.a; + sunion.a; //[mir]~ ERROR cannot use `sunion.a` because it was mutably borrowed (Mir) + } + // Deref and field from struct + { + let mut f = Box::new(Foo { x: 22 }); + let _x = f.x(); + f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed + //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `f.x` because it was mutably borrowed (Mir) + } + // Deref and field from tuple-struct + { + let mut g = Box::new(Bar(22)); + let _0 = g.x(); + g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `g.0` because it was mutably borrowed (Mir) + } + // Deref and field from tuple + { + let mut h = Box::new((22, 23)); + let _0 = &mut h.0; + h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed + //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `h.0` because it was mutably borrowed (Mir) + } + // Deref and field from enum + { + let mut e = Box::new(Baz::X(3)); + let _e0 = e.x(); + match *e { + Baz::X(value) => value + //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `e.0` because it was mutably borrowed (Mir) + }; + } + // Deref and field from union + unsafe { + let mut u = Box::new(U { b: 0 }); + let _ra = &mut u.a; + u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed + //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) + } + // Constant index + { + let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let _v = &mut v; + match v { + &[x, _, .., _, _] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, x, .., _, _] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, _, .., x, _] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, _, .., _, x] => println!("{}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + } + // Subslices + { + let mut v = &[1, 2, 3, 4, 5]; + let _v = &mut v; + match v { + &[x..] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, x..] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[x.., _] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + match v { + &[_, x.., _] => println!("{:?}", x), + //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + } + // Downcasted field + { + enum E { A(X), B { x: X } } + + let mut e = E::A(3); + let _e = &mut e; + match e { + E::A(ref ax) => + //[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable (Mir) + //[mir]~| ERROR cannot use `e` because it was mutably borrowed (Mir) + println!("e.ax: {:?}", ax), + E::B { x: ref bx } => + //[ast]~^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable (Mir) + println!("e.bx: {:?}", bx), + } + } + // Field in field + { + struct F { x: u32, y: u32 }; + struct S { x: F, y: (u32, u32), }; + let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) }; + let _s = &mut s; + match s { + S { y: (ref y0, _), .. } => + //[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable (Mir) + println!("y0: {:?}", y0), + _ => panic!("other case"), + } + match s { + S { x: F { y: ref x0, .. }, .. } => + //[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable + //[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable (Ast) + //[mir]~| ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable (Mir) + println!("x0: {:?}", x0), + _ => panic!("other case"), + } + } + // Field of ref + { + struct Block<'a> { + current: &'a u8, + unrelated: &'a u8, + }; + + fn bump<'a>(mut block: &mut Block<'a>) { + let x = &mut block; + let p: &'a u8 = &*block.current; + //[mir]~^ ERROR cannot borrow `(*block.current)` as immutable because it is also borrowed as mutable (Mir) + // No errors in AST because of issue rust#38899 + } + } + // Field of ptr + { + struct Block2 { + current: *const u8, + unrelated: *const u8, + } + + unsafe fn bump2(mut block: *mut Block2) { + let x = &mut block; + let p : *const u8 = &*(*block).current; + //[mir]~^ ERROR cannot borrow `(*block.current)` as immutable because it is also borrowed as mutable (Mir) + // No errors in AST because of issue rust#38899 + } + } + // Field of index + { + struct F {x: u32, y: u32}; + let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; + let _v = &mut v; + v[0].y; + //[ast]~^ ERROR cannot use `v[..].y` because it was mutably borrowed + //[mir]~^^ ERROR cannot use `v[..].y` because it was mutably borrowed (Ast) + //[mir]~| ERROR cannot use `v[..].y` because it was mutably borrowed (Mir) + //[mir]~| ERROR cannot use `(*v)` because it was mutably borrowed (Mir) + } + // Field of constant index + { + struct F {x: u32, y: u32}; + let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; + let _v = &mut v; + match v { + &[_, F {x: ref xf, ..}] => println!("{}", xf), + //[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable (Mir) + // No errors in AST + _ => panic!("other case") + } + } +} diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs index 73d323ea82cfb..0655d2914eefa 100644 --- a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs @@ -34,13 +34,13 @@ fn main() { let ra = &u.a; let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable (Ast) - //[mir]~| ERROR cannot borrow `u.0` as mutable because it is also borrowed as immutable (Mir) + //[mir]~| ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable (Mir) } { let ra = &u.a; u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `u.0` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `u.a` because it is borrowed (Mir) } // Imm borrow, other field { @@ -68,25 +68,25 @@ fn main() { let rma = &mut u.a; let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable (Ast) - //[mir]~| ERROR cannot borrow `u.0` as immutable because it is also borrowed as mutable (Mir) + //[mir]~| ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable (Mir) } { let ra = &mut u.a; let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast) - //[mir]~| ERROR cannot use `u.0` because it was mutably borrowed (Mir) + //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir) } { let rma = &mut u.a; let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time (Ast) - //[mir]~| ERROR cannot borrow `u.0` as mutable more than once at a time (Mir) + //[mir]~| ERROR cannot borrow `u.a` as mutable more than once at a time (Mir) } { let rma = &mut u.a; u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed (Ast) - //[mir]~| ERROR cannot assign to `u.0` because it is borrowed (Mir) + //[mir]~| ERROR cannot assign to `u.a` because it is borrowed (Mir) } // Mut borrow, other field {