about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs82
-rw-r--r--src/test/ui/not-copy-closure.nll.stderr6
2 files changed, 49 insertions, 39 deletions
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index ad8abe16415..474e67ac11a 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -123,7 +123,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 Origin::Mir,
             );
 
-            self.add_closure_invoked_twice_with_moved_variable_suggestion(
+            self.add_moved_or_invoked_closure_note(
                 context.loc,
                 used_place,
                 &mut err,
@@ -1329,7 +1329,8 @@ enum StorageDeadOrDrop<'tcx> {
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
-    /// Adds a suggestion when a closure is invoked twice with a moved variable.
+    /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
+    /// is moved after being invoked.
     ///
     /// ```text
     /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
@@ -1339,30 +1340,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// LL |         for (key, value) in dict {
     ///    |                             ^^^^
     /// ```
-    pub(super) fn add_closure_invoked_twice_with_moved_variable_suggestion(
+    pub(super) fn add_moved_or_invoked_closure_note(
         &self,
         location: Location,
         place: &Place<'tcx>,
         diag: &mut DiagnosticBuilder<'_>,
     ) {
+        debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
         let mut target = place.local();
-        debug!(
-            "add_closure_invoked_twice_with_moved_variable_suggestion: location={:?} place={:?} \
-             target={:?}",
-             location, place, target,
-        );
         for stmt in &self.mir[location.block].statements[location.statement_index..] {
-            debug!(
-                "add_closure_invoked_twice_with_moved_variable_suggestion: stmt={:?} \
-                 target={:?}",
-                 stmt, target,
-            );
+            debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
             if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind {
-                debug!(
-                    "add_closure_invoked_twice_with_moved_variable_suggestion: into={:?} \
-                     from={:?}",
-                     into, from,
-                );
+                debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
                 match from {
                     Operand::Copy(ref place) |
                     Operand::Move(ref place) if target == place.local() =>
@@ -1372,12 +1361,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             }
         }
 
-
+        // Check if we are attempting to call a closure after it has been invoked.
         let terminator = self.mir[location.block].terminator();
-        debug!(
-            "add_closure_invoked_twice_with_moved_variable_suggestion: terminator={:?}",
-            terminator,
-        );
+        debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
         if let TerminatorKind::Call {
             func: Operand::Constant(box Constant {
                 literal: ty::LazyConst::Evaluated(ty::Const {
@@ -1389,7 +1375,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             args,
             ..
         } = &terminator.kind {
-            debug!("add_closure_invoked_twice_with_moved_variable_suggestion: id={:?}", id);
+            debug!("add_moved_or_invoked_closure_note: id={:?}", id);
             if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
                 let closure = match args.first() {
                     Some(Operand::Copy(ref place)) |
@@ -1397,33 +1383,51 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         place.local().unwrap(),
                     _ => return,
                 };
-                debug!(
-                    "add_closure_invoked_twice_with_moved_variable_suggestion: closure={:?}",
-                     closure,
-                );
 
-                if let ty::TyKind::Closure(did, _substs) = self.mir.local_decls[closure].ty.sty {
-                    let node_id = match self.infcx.tcx.hir().as_local_node_id(did) {
-                        Some(node_id) => node_id,
-                        _ => return,
-                    };
+                debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
+                if let ty::TyKind::Closure(did, _) = self.mir.local_decls[closure].ty.sty {
+                    let node_id = self.infcx.tcx.hir().as_local_node_id(did).unwrap();
                     let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id);
 
-                    if let Some((
-                        span, name
-                    )) = self.infcx.tcx.typeck_tables_of(did).closure_kind_origins().get(hir_id) {
+                    if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
+                        .closure_kind_origins()
+                        .get(hir_id)
+                    {
                         diag.span_note(
                             *span,
                             &format!(
-                                "closure cannot be invoked more than once because it \
-                                 moves the variable `{}` out of its environment",
-                                 name,
+                                "closure cannot be invoked more than once because it moves the \
+                                 variable `{}` out of its environment",
+                                name,
                             ),
                         );
+                        return;
                     }
                 }
             }
         }
+
+        // Check if we are just moving a closure after it has been invoked.
+        if let Some(target) = target {
+            if let ty::TyKind::Closure(did, _) = self.mir.local_decls[target].ty.sty {
+                let node_id = self.infcx.tcx.hir().as_local_node_id(did).unwrap();
+                let hir_id = self.infcx.tcx.hir().node_to_hir_id(node_id);
+
+                if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
+                    .closure_kind_origins()
+                    .get(hir_id)
+                {
+                    diag.span_note(
+                        *span,
+                        &format!(
+                            "closure cannot be moved more than once as it is not `Copy` due to \
+                             moving the variable `{}` out of its environment",
+                             name
+                        ),
+                    );
+                }
+            }
+        }
     }
 
     /// End-user visible description of `place` if one can be found. If the
diff --git a/src/test/ui/not-copy-closure.nll.stderr b/src/test/ui/not-copy-closure.nll.stderr
index 2f295315a08..1a65bcf4473 100644
--- a/src/test/ui/not-copy-closure.nll.stderr
+++ b/src/test/ui/not-copy-closure.nll.stderr
@@ -5,6 +5,12 @@ LL |     let b = hello;
    |             ----- value moved here
 LL |     let c = hello; //~ ERROR use of moved value: `hello` [E0382]
    |             ^^^^^ value used here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment
+  --> $DIR/not-copy-closure.rs:6:9
+   |
+LL |         a += 1;
+   |         ^
 
 error: aborting due to previous error