diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index e972b02b581f7..5991845d265b2 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -151,25 +151,10 @@ impl<'tcx> Place<'tcx> { } }, _ => None, - }, + } _ => None, } } - - /// Strip the deref projections from a `Place`. For example, given `(*(*((*_1).0: &&T)))`, this - /// will return `((*_1).0)`. Once stripped of any deref projections, places can then be - /// checked as upvar field projections using `is_upvar_field_projection`. - pub fn strip_deref_projections(&self) -> &Place<'tcx> { - let mut current = self; - while let Place::Projection(ref proj) = current { - if let ProjectionElem::Deref = proj.elem { - current = &proj.base; - } else { - break; - } - } - current - } } pub enum RvalueInitializationState { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 2c3bf83fc2a40..d3524e841b223 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -16,6 +16,7 @@ use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; use borrow_check::MirBorrowckCtxt; +use borrow_check::prefixes::PrefixSet; use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind}; use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex}; use util::borrowck_errors::{BorrowckErrors, Origin}; @@ -254,15 +255,16 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // 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); + let is_upvar_field_projection = + self.prefixes(&original_path, PrefixSet::All) + .any(|p| p.is_upvar_field_projection(self.mir, &self.tcx) + .is_some()); 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() && - original_path.strip_deref_projections() - .is_upvar_field_projection(self.mir, &self.tcx) - .is_some() + if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection => { let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); @@ -286,13 +288,18 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let mut diag = self.tcx.cannot_move_out_of( span, place_description, origin); - if let Some(field) = original_path.is_upvar_field_projection( - self.mir, &self.tcx) { - let upvar_decl = &self.mir.upvar_decls[field.index()]; - let upvar_hir_id = upvar_decl.var_hir_id.assert_crate_local(); - let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id); - let upvar_span = self.tcx.hir.span(upvar_node_id); - diag.span_label(upvar_span, "captured outer variable"); + for prefix in self.prefixes(&original_path, PrefixSet::All) { + if let Some(field) = prefix.is_upvar_field_projection( + self.mir, &self.tcx) { + let upvar_decl = &self.mir.upvar_decls[field.index()]; + let upvar_hir_id = + upvar_decl.var_hir_id.assert_crate_local(); + let upvar_node_id = + self.tcx.hir.hir_to_node_id(upvar_hir_id); + let upvar_span = self.tcx.hir.span(upvar_node_id); + diag.span_label(upvar_span, "captured outer variable"); + break; + } } diag diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr index f5b7ca22278e4..9f56b26648b2a 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr @@ -1,6 +1,9 @@ error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/borrowck-move-by-capture.rs:19:29 | +LL | let bar: Box<_> = box 3; + | --- captured outer variable +LL | let _g = to_fn_mut(|| { LL | let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of captured variable in an `FnMut` closure diff --git a/src/test/ui/issues/issue-4335.nll.stderr b/src/test/ui/issues/issue-4335.nll.stderr index 4ccd24fa45921..a9345e86f7248 100644 --- a/src/test/ui/issues/issue-4335.nll.stderr +++ b/src/test/ui/issues/issue-4335.nll.stderr @@ -1,6 +1,8 @@ error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/issue-4335.rs:16:20 | +LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { + | - captured outer variable LL | id(Box::new(|| *v)) | ^^ cannot move out of captured variable in an `FnMut` closure diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr index 4f2220b0de341..13a6fc15ce318 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr @@ -1,6 +1,8 @@ error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:21:28 | +LL | let i = box 3; + | - captured outer variable LL | let _f = to_fn(|| test(i)); //~ ERROR cannot move out | ^ cannot move out of captured variable in an `Fn` closure diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs new file mode 100644 index 0000000000000..dc40b0c44fd02 --- /dev/null +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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. + +#![feature(nll)] + +fn expect_fn(f: F) where F : Fn() { + f(); +} + +fn main() { + { + let x = (vec![22], vec![44]); + expect_fn(|| drop(x.0)); + //~^ ERROR cannot move out of captured variable in an `Fn` closure [E0507] + } +} diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr new file mode 100644 index 0000000000000..51f19565855a7 --- /dev/null +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -0,0 +1,11 @@ +error[E0507]: cannot move out of captured variable in an `Fn` closure + --> $DIR/issue-52663-span-decl-captured-variable.rs:20:26 + | +LL | let x = (vec![22], vec![44]); + | - captured outer variable +LL | expect_fn(|| drop(x.0)); + | ^^^ cannot move out of captured variable in an `Fn` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr index e74c66c27b136..4baa54e34c755 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr @@ -1,24 +1,32 @@ error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:25:31 | +LL | let x = Box::new(0); + | - captured outer variable LL | let f = to_fn(|| drop(x)); //~ ERROR cannot move | ^ cannot move out of captured variable in an `Fn` closure error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:29:35 | +LL | let x = Box::new(0); + | - captured outer variable LL | let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move | ^ cannot move out of captured variable in an `FnMut` closure error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:38:36 | +LL | let x = Box::new(0); + | - captured outer variable LL | let f = to_fn(move || drop(x)); //~ ERROR cannot move | ^ cannot move out of captured variable in an `Fn` closure error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:42:40 | +LL | let x = Box::new(0); + | - captured outer variable LL | let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move | ^ cannot move out of captured variable in an `FnMut` closure