about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-08-07 19:50:19 +0200
committerDavid Wood <david@davidtw.co>2018-08-14 18:38:57 +0200
commit5532e9dec5b2ccb8c746108051f6d0d5378c3b8e (patch)
treeeec3d05bfa15ec665994ace8bb56b25263e2ca58
parent2c6b0e5cf7d07cee4b26732c162b5835ab5aa53b (diff)
downloadrust-5532e9dec5b2ccb8c746108051f6d0d5378c3b8e.tar.gz
rust-5532e9dec5b2ccb8c746108051f6d0d5378c3b8e.zip
Improved how upvars are detected when presenting errors using prefixes.
-rw-r--r--src/librustc/mir/tcx.rs17
-rw-r--r--src/librustc_mir/borrow_check/move_errors.rs29
-rw-r--r--src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr3
-rw-r--r--src/test/ui/issues/issue-4335.nll.stderr2
-rw-r--r--src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr2
-rw-r--r--src/test/ui/nll/issue-52663-span-decl-captured-variable.rs23
-rw-r--r--src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr11
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr8
8 files changed, 68 insertions, 27 deletions
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index e972b02b581..5991845d265 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 2c3bf83fc2a..d3524e841b2 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 f5b7ca22278..9f56b26648b 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 4ccd24fa459..a9345e86f72 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<FnMut() -> 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 4f2220b0de3..13a6fc15ce3 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 00000000000..dc40b0c44fd
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+fn expect_fn<F>(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 00000000000..51f19565855
--- /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 e74c66c27b1..4baa54e34c7 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