From aa78919733264bfd07e49c7ed8e82f5a5a9eed11 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Mon, 2 Oct 2017 19:36:58 +0200 Subject: [PATCH 01/12] mir-borrowck: print values in error messages in the same way that the AST borrowck - Print fields with `.name` rather than `.` - Autoderef values if followed by a field or an index --- src/librustc_mir/borrow_check.rs | 101 ++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 14b6e31913250..f4bf280cd25ce 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1053,12 +1053,12 @@ 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]; @@ -1071,15 +1071,25 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> 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::Field(field, _ty) => { + autoderef = true; + ("", format!(".{}", self.describe_field(&proj.base, field.index())), None) + }, + ProjectionElem::Index(index) => { + autoderef = true; + ("", 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 } => @@ -1092,10 +1102,10 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> ("", format!("[{}:-{}]", from, to), 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_lvalue_to_string(&Lvalue::Local(index), buf, None); buf.push_str("]"); } else { buf.push_str(&suffix); @@ -1104,6 +1114,77 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> } } + // 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(..) => { + debug!("End-user description not implemented for field of projection {:?}", + proj); + format!("{}", field_index) + }, + ProjectionElem::Field(..) => { + debug!("End-user description not implemented for field of projection {:?}", + proj); + format!("{}", field_index) + }, + ProjectionElem::Index(..) => { + debug!("End-user description not implemented for field of projection {:?}", + proj); + format!("{}", field_index) + }, + ProjectionElem::ConstantIndex { .. } => { + debug!("End-user description not implemented for field of projection {:?}", + proj); + format!("{}", field_index) + }, + ProjectionElem::Subslice { .. } => { + debug!("End-user description not implemented for field of projection {:?}", + proj); + format!("{}", 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) + }, + _ => { + debug!("End-user description not implemented for field of type {:?}", ty.sty); + format!("{}", field_index) + } + } + } + } + // 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] From ff8ea69d8f52935345f74241bb524383a47bd1d7 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Mon, 2 Oct 2017 19:39:43 +0200 Subject: [PATCH 02/12] mir-borrowck: Add tests for `describe_lvalue()` --- .../borrowck/borrowck-describe-lvalue.rs | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs 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..6de8bda9276af --- /dev/null +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -0,0 +1,166 @@ +// 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. + +// revisions: ast mir +//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir + +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) + } +} From 7bdf177c8fe045508eff5fe767f00be3f1fca92d Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Mon, 2 Oct 2017 19:40:08 +0200 Subject: [PATCH 03/12] mir-borrowck: Fix existing tests --- .../compile-fail/borrowck/borrowck-assign-comp.rs | 4 ++-- .../borrowck/borrowck-closures-mut-and-imm.rs | 2 +- .../compile-fail/borrowck/borrowck-union-borrow.rs | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) 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-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 { From 456e12ec38f669b26b08414527ee1dc35091da33 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Wed, 4 Oct 2017 18:02:36 +0200 Subject: [PATCH 04/12] mir-borrowck: Panic when trying to print a field access on a non-box type that is neither Adt nor tuple --- src/librustc_mir/borrow_check.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index f4bf280cd25ce..18bb78ef50f09 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1178,8 +1178,10 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> format!("{}", field_index) }, _ => { - debug!("End-user description not implemented for field of type {:?}", ty.sty); - format!("{}", field_index) + // Might need a revision when the fields in trait RFC is implemented + // (https://github.com/rust-lang/rfcs/pull/1546) + bug!("Field access unsupported for non-box types that are neither Adt (struct, \ + enum, union) nor tuples"); } } } From ef2f42d04a4c83dd5b50cd672b8a1b0791e00f98 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Thu, 5 Oct 2017 11:03:32 +0200 Subject: [PATCH 05/12] mir-borrowck: Autoderef values followed by a constant index, and fix reported lvalue for constant index Previously the constant index was reported as `[x of y]` or `[-x of y]` where `x` was the offset and `y` the minimum length of the slice. The minus sign wasn't in the right case since for `&[_, x, .., _, _]`, the error reported was `[-1 of 4]`, and for `&[_, _, .., x, _]`, the error reported was `[2 of 4]`. This commit fixes the sign so that the indexes 1 and -2 are reported, and remove the ` of y` part of the message to make it more succinct. --- src/librustc_mir/borrow_check.rs | 12 ++++--- .../borrowck/borrowck-describe-lvalue.rs | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 18bb78ef50f09..85ecb9d6e3670 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1090,10 +1090,14 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> autoderef = true; ("", 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::ConstantIndex { offset, from_end: false, .. } => { + autoderef = true; + ("", format!("[{}]", offset), None) + }, + ProjectionElem::ConstantIndex { offset, from_end: true, .. } => { + autoderef = true; + ("", format!("[-{}]", offset), None) + }, ProjectionElem::Subslice { from, to: 0 } => ("", format!("[{}:]", from), None), ProjectionElem::Subslice { from: 0, to } => diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 6de8bda9276af..9d1b2b64d850a 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -11,6 +11,8 @@ // revisions: ast mir //[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir +#![feature(advanced_slice_patterns)] + pub struct Foo { x: u32 } @@ -163,4 +165,37 @@ fn main() { //[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[0]` 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[1]` 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[-2]` 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[-1]` because it was mutably borrowed (Mir) + _ => panic!("other case"), + } + } } From 0241ea45b2e71e53921627bc09219653f2629c0e Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 17:21:06 +0200 Subject: [PATCH 06/12] mir-borrowck: Replace all constant index and sublices output with `[..]` to match the AST borrowck output --- src/librustc_mir/borrow_check.rs | 17 +++----- .../borrowck/borrowck-describe-lvalue.rs | 43 +++++++++++++++++-- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 85ecb9d6e3670..d57bac7c85a52 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1090,20 +1090,13 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> autoderef = true; ("", format!(""), Some(index)) }, - ProjectionElem::ConstantIndex { offset, from_end: false, .. } => { + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; - ("", format!("[{}]", offset), None) + // 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) }, - ProjectionElem::ConstantIndex { offset, from_end: true, .. } => { - autoderef = true; - ("", format!("[-{}]", offset), 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), }; buf.push_str(prefix); self.append_lvalue_to_string(&proj.base, buf, Some(autoderef)); diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 9d1b2b64d850a..088b678efb566 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -8,9 +8,11 @@ // 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 { @@ -173,29 +175,62 @@ fn main() { &[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[0]` because it was mutably borrowed (Mir) + //[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[1]` because it was mutably borrowed (Mir) + //[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[-2]` because it was mutably borrowed (Mir) + //[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[-1]` because it was mutably borrowed (Mir) + //[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"), + } + } } From f35c4e3aa168e1d5d78753ae1d12e8f25cbec699 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 17:24:23 +0200 Subject: [PATCH 07/12] mir-borrowck: Implement end-user output for field of downcast projection --- src/librustc_mir/borrow_check.rs | 7 ++----- .../borrowck/borrowck-describe-lvalue.rs | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index d57bac7c85a52..62e73557b2577 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1125,11 +1125,6 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field_index), - ProjectionElem::Downcast(..) => { - debug!("End-user description not implemented for field of projection {:?}", - proj); - format!("{}", field_index) - }, ProjectionElem::Field(..) => { debug!("End-user description not implemented for field of projection {:?}", proj); @@ -1145,6 +1140,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> proj); format!("{}", field_index) }, + ProjectionElem::Downcast(def, variant_index) => + format!("{}", def.variants[variant_index].fields[field_index].name), ProjectionElem::Subslice { .. } => { debug!("End-user description not implemented for field of projection {:?}", proj); diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 088b678efb566..7ea965b07be4b 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -233,4 +233,24 @@ fn main() { _ => 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), + } + } } From ce3b2e779e56b99a682086d7d9575260158f1ad1 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 17:25:41 +0200 Subject: [PATCH 08/12] mir-borrowck: Implement end-user output for field of field projection --- src/librustc_mir/borrow_check.rs | 7 ++---- .../borrowck/borrowck-describe-lvalue.rs | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 62e73557b2577..384b1fb418cfd 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1125,11 +1125,6 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field_index), - ProjectionElem::Field(..) => { - debug!("End-user description not implemented for field of projection {:?}", - proj); - format!("{}", field_index) - }, ProjectionElem::Index(..) => { debug!("End-user description not implemented for field of projection {:?}", proj); @@ -1142,6 +1137,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> }, 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::Subslice { .. } => { debug!("End-user description not implemented for field of projection {:?}", proj); diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 7ea965b07be4b..103aad693f782 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -253,4 +253,27 @@ fn main() { 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"), + } + } } From 9ce2f3af9379246909d3e0151b956ad428bbc175 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 17:26:14 +0200 Subject: [PATCH 09/12] mir-borrowck: Implement end-user output for field of index projection --- src/librustc_mir/borrow_check.rs | 12 ++-------- .../borrowck/borrowck-describe-lvalue.rs | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 384b1fb418cfd..0d9dbfab1e888 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1125,20 +1125,12 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field_index), - ProjectionElem::Index(..) => { - debug!("End-user description not implemented for field of projection {:?}", - proj); - format!("{}", field_index) - }, - ProjectionElem::ConstantIndex { .. } => { - debug!("End-user description not implemented for field of projection {:?}", - proj); - format!("{}", 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 { .. } => + format!("{}", self.describe_field(&proj.base, field_index)), ProjectionElem::Subslice { .. } => { debug!("End-user description not implemented for field of projection {:?}", proj); diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 103aad693f782..7ead9032c135b 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -276,4 +276,27 @@ fn main() { _ => panic!("other case"), } } + // 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") + } + } } From ca5dc86c5a2e92f35c94e7a1f4592bb7fd0b271c Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 17:26:53 +0200 Subject: [PATCH 10/12] mir-borrowck: Implement end-user output for field of reference, pointer and array --- src/librustc_mir/borrow_check.rs | 9 ++++-- .../borrowck/borrowck-describe-lvalue.rs | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 0d9dbfab1e888..eb05a815c7386 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1160,11 +1160,16 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> ty::TyTuple(_, _) => { format!("{}", field_index) }, + ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => { + self.describe_field_from_ty(&tnm.ty, field_index) + }, + ty::TyArray(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!("Field access unsupported for non-box types that are neither Adt (struct, \ - enum, union) nor tuples"); + bug!("End-user description not implemented for field access on `{:?}`", ty.sty); } } } diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs index 7ead9032c135b..cff913b17bedd 100644 --- a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs @@ -276,6 +276,34 @@ fn main() { _ => 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}; From 8b8cdd984aa31eebccea2a9fb5c1f7931dd01c27 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 17:29:14 +0200 Subject: [PATCH 11/12] mir-borrowck: Append `_` or `..` depending on the context if a local variable hasn't a name --- src/librustc_mir/borrow_check.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index eb05a815c7386..3546b9985327b 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}; @@ -1061,11 +1061,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> 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))); @@ -1102,7 +1098,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> 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, None); + self.append_local_to_string(index, buf, ".."); buf.push_str("]"); } else { buf.push_str(&suffix); @@ -1111,6 +1107,16 @@ 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 { From e32e81c9da5adcc77bd12192d45d2d4af54d0ee9 Mon Sep 17 00:00:00 2001 From: Basile Desloges Date: Fri, 6 Oct 2017 18:23:53 +0200 Subject: [PATCH 12/12] mir-borrowck: Implement end-user output for field of subslice and slice type --- src/librustc_mir/borrow_check.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 3546b9985327b..14e6f59782651 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1135,13 +1135,10 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> 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::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => format!("{}", self.describe_field(&proj.base, field_index)), - ProjectionElem::Subslice { .. } => { - debug!("End-user description not implemented for field of projection {:?}", - proj); - format!("{}", field_index) - } } } } @@ -1169,7 +1166,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => { self.describe_field_from_ty(&tnm.ty, field_index) }, - ty::TyArray(ty, _) => { + ty::TyArray(ty, _) | ty::TySlice(ty) => { self.describe_field_from_ty(&ty, field_index) } _ => {