about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2018-05-31 12:46:43 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2018-06-06 22:42:27 +0200
commitfbe7d5bce8f618ce0fc8d78d4153c05dc85e62bb (patch)
treef2f130fd1fd29b931066929538dfac60a7befd4d
parentcb8ab33ed29544973da866bdc3eff509b3c3e789 (diff)
downloadrust-fbe7d5bce8f618ce0fc8d78d4153c05dc85e62bb.tar.gz
rust-fbe7d5bce8f618ce0fc8d78d4153c05dc85e62bb.zip
When NLL has illegal move due to borrowed content, provide feedback about why the move wasn't a copy.
This should address #51190.
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs13
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs9
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs16
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs8
5 files changed, 37 insertions, 11 deletions
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index 18026a14259..84931907964 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -147,7 +147,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
         }
         Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
             bccx.cannot_move_out_of_interior_noncopy(
-                move_from.span, b.ty, ik == Kind::Index, Origin::Ast)
+                move_from.span, b.ty, Some(ik == Kind::Index), Origin::Ast)
         }
 
         Categorization::Downcast(ref b, _) |
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 5efbdeafd1b..ba0557d062f 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -132,14 +132,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
                     IllegalMoveOriginKind::Static => {
                         tcx.cannot_move_out_of(span, "static item", origin)
                     }
-                    IllegalMoveOriginKind::BorrowedContent => {
-                        tcx.cannot_move_out_of(span, "borrowed content", origin)
+                    IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => {
+                        // Inspect the type of the content behind the
+                        // borrow to provide feedback about why this
+                        // was a move rather than a copy.
+                        match ty.sty {
+                            ty::TyArray(..) | ty::TySlice(..) =>
+                                tcx.cannot_move_out_of_interior_noncopy(span, ty, None, origin),
+                            _ => tcx.cannot_move_out_of(span, "borrowed content", origin)
+                        }
                     }
                     IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
                         tcx.cannot_move_out_of_interior_of_drop(span, ty, origin)
                     }
                     IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
-                        tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin)
+                        tcx.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index), origin)
                     }
                 };
                 err.emit();
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 2ff22842141..590f9917015 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -119,8 +119,8 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
     }
 
     fn create_move_path(&mut self, place: &Place<'tcx>) {
-        // This is an assignment, not a move, so this not being a valid
-        // move path is OK.
+        // This is an non-moving access (such as an overwrite or
+        // drop), so this not being a valid move path is OK.
         let _ = self.move_path_for(place);
     }
 
@@ -135,8 +135,9 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
         let place_ty = proj.base.ty(mir, tcx).to_ty(tcx);
         match place_ty.sty {
             ty::TyRef(..) | ty::TyRawPtr(..) =>
-                return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
-                                                         BorrowedContent)),
+                return Err(MoveError::cannot_move_out_of(
+                    mir.source_info(self.loc).span,
+                    BorrowedContent { target_ty: place.ty(mir, tcx).to_ty(tcx) })),
             ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
                 return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
                                                          InteriorOfTypeWithDestructor {
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index 610963af9e1..a73e47bc16a 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -277,9 +277,23 @@ pub struct IllegalMoveOrigin<'tcx> {
 
 #[derive(Debug)]
 pub(crate) enum IllegalMoveOriginKind<'tcx> {
+    /// Illegal move due to attempt to move from `static` variable.
     Static,
-    BorrowedContent,
+
+    /// 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>,
+    },
+
+    /// Illegal move due to attempt to move from field of an ADT that
+    /// implements `Drop`. Rust maintains invariant that all `Drop`
+    /// ADT's remain fully-initialized so that user-defined destructor
+    /// can safely read from all of the ADT's fields.
     InteriorOfTypeWithDestructor { container_ty: ty::Ty<'tcx> },
+
+    /// Illegal move due to attempt to move out of a slice or array.
     InteriorOfSliceOrArray { ty: ty::Ty<'tcx>, is_index: bool, },
 }
 
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index d6b3e674f8f..d01b90ad262 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -312,15 +312,19 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         self.cancel_if_wrong_origin(err, o)
     }
 
+    /// Signal an error due to an attempt to move out of the interior
+    /// of an array or slice. `is_index` is None when error origin
+    /// didn't capture whether there was an indexing operation or not.
     fn cannot_move_out_of_interior_noncopy(self,
                                            move_from_span: Span,
                                            ty: ty::Ty,
-                                           is_index: bool,
+                                           is_index: Option<bool>,
                                            o: Origin)
                                            -> DiagnosticBuilder<'cx>
     {
         let type_name = match (&ty.sty, is_index) {
-            (&ty::TyArray(_, _), true) => "array",
+            (&ty::TyArray(_, _), Some(true)) |
+            (&ty::TyArray(_, _), None) => "array",
             (&ty::TySlice(_),    _) => "slice",
             _ => span_bug!(move_from_span, "this path should not cause illegal move"),
         };