From 12412749ab209447611c6d071e187d787c6feeb2 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 13 Jul 2018 23:39:10 +0100 Subject: [PATCH] Add specific message when moving from upvars in a non-FnOnce closure --- src/librustc_mir/borrow_check/move_errors.rs | 32 ++++++++++++++++++- .../dataflow/move_paths/builder.rs | 4 +-- src/librustc_mir/dataflow/move_paths/mod.rs | 6 ++-- .../ui/borrowck/borrowck-in-static.nll.stderr | 4 +-- ...upvar-from-non-once-ref-closure.nll.stderr | 4 +-- src/test/ui/error-codes/E0161.nll.stderr | 16 ---------- src/test/ui/issue-4335.nll.stderr | 4 +-- ...owck-call-is-borrow-issue-12224.nll.stderr | 4 +-- 8 files changed, 44 insertions(+), 30 deletions(-) delete mode 100644 src/test/ui/error-codes/E0161.nll.stderr diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index d979851376a..0b49260f88a 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -11,6 +11,7 @@ use rustc::hir; use rustc::mir::*; use rustc::ty; +use rustc_data_structures::indexed_vec::Idx; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -230,14 +231,43 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { IllegalMoveOriginKind::Static => { self.tcx.cannot_move_out_of(span, "static item", origin) } - IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => { + IllegalMoveOriginKind::BorrowedContent { target_place: place } => { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. + let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { ty::TyArray(..) | ty::TySlice(..) => self .tcx .cannot_move_out_of_interior_noncopy(span, ty, None, origin), + ty::TyClosure(def_id, closure_substs) + if !self.mir.upvar_decls.is_empty() + && { + match place { + Place::Projection(ref proj) => { + proj.base == Place::Local(Local::new(1)) + } + Place::Local(_) | Place::Static(_) => unreachable!(), + } + } => + { + let closure_kind_ty = + closure_substs.closure_kind_ty(def_id, self.tcx); + let closure_kind = closure_kind_ty.to_opt_closure_kind(); + let place_description = match closure_kind { + Some(ty::ClosureKind::Fn) => { + "captured variable in an `Fn` closure" + } + Some(ty::ClosureKind::FnMut) => { + "captured variable in an `FnMut` closure" + } + Some(ty::ClosureKind::FnOnce) => { + bug!("closure kind does not match first argument type") + } + None => bug!("closure kind not inferred by borrowck"), + }; + self.tcx.cannot_move_out_of(span, place_description, origin) + } _ => self .tcx .cannot_move_out_of(span, "borrowed content", origin), diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 9ffbe21e1e2..48236e5fdd1 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -132,11 +132,11 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let mir = self.builder.mir; let tcx = self.builder.tcx; let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); - match place_ty.sty { + match place_ty.sty { ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MoveError::cannot_move_out_of( self.loc, - BorrowedContent { target_ty: place.ty(mir, tcx).to_ty(tcx) })), + BorrowedContent { target_place: place.clone() })), ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => return Err(MoveError::cannot_move_out_of(self.loc, InteriorOfTypeWithDestructor { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 3051a687eac..54609674a47 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -282,9 +282,9 @@ pub(crate) enum IllegalMoveOriginKind<'tcx> { /// Illegal move due to attempt to move from behind a reference. BorrowedContent { - /// The content's type: if erroneous code was trying to move - /// from `*x` where `x: &T`, then this will be `T`. - target_ty: ty::Ty<'tcx>, + /// The place the reference refers to: if erroneous code was trying to + /// move from `(*x).f` this will be `*x`. + target_place: Place<'tcx>, }, /// Illegal move due to attempt to move from field of an ADT that diff --git a/src/test/ui/borrowck/borrowck-in-static.nll.stderr b/src/test/ui/borrowck/borrowck-in-static.nll.stderr index 927d8c37458..05a022a726c 100644 --- a/src/test/ui/borrowck/borrowck-in-static.nll.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.nll.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/borrowck-in-static.rs:15:17 | LL | Box::new(|| x) //~ ERROR cannot move out of captured outer variable - | ^ cannot move out of borrowed content + | ^ cannot move out of captured variable in an `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr index 7464e33e8c1..07a9f374b2c 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:21:9 | LL | y.into_iter(); - | ^ cannot move out of borrowed content + | ^ cannot move out of captured variable in an `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr deleted file mode 100644 index 6aaff743383..00000000000 --- a/src/test/ui/error-codes/E0161.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0507]: cannot move out of borrowed content - --> $DIR/E0161.rs:14:28 - | -LL | let _x: Box = box *"hello"; //~ ERROR E0161 - | ^^^^^^^^ cannot move out of borrowed content - -error[E0161]: cannot move a value of type str: the size of str cannot be statically determined - --> $DIR/E0161.rs:14:28 - | -LL | let _x: Box = box *"hello"; //~ ERROR E0161 - | ^^^^^^^^ - -error: aborting due to 2 previous errors - -Some errors occurred: E0161, E0507. -For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/issue-4335.nll.stderr b/src/test/ui/issue-4335.nll.stderr index 8eede347478..eacd8b5e580 100644 --- a/src/test/ui/issue-4335.nll.stderr +++ b/src/test/ui/issue-4335.nll.stderr @@ -1,8 +1,8 @@ -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/issue-4335.rs:16:20 | LL | id(Box::new(|| *v)) - | ^^ cannot move out of borrowed content + | ^^ cannot move out of captured variable in an `FnMut` closure error[E0597]: `v` does not live long enough --> $DIR/issue-4335.rs:16:17 diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr index f752015c650..b3563f1b620 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr @@ -28,11 +28,11 @@ LL | fn test4(f: &Test) { LL | f.f.call_mut(()) | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0507]: cannot move out of borrowed content +error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13 | LL | foo(f); - | ^ cannot move out of borrowed content + | ^ cannot move out of captured variable in an `FnMut` closure error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:65:16