about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-06-11 13:48:46 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-06-26 16:28:09 -0400
commitfa6a61c68930b390407d73e0ba71f2af5555f0f0 (patch)
tree9d1ad6feeb72a826ca906a1a25a5271f5242a9b7
parent36ac08e2643dc5cc035031007a8a36f4c87d3543 (diff)
downloadrust-fa6a61c68930b390407d73e0ba71f2af5555f0f0.tar.gz
rust-fa6a61c68930b390407d73e0ba71f2af5555f0f0.zip
Explain move errors that occur due to method calls involving `self`
This is a re-attempt of #72389 (which was reverted in #73594)
Instead of using `ExpnKind::Desugaring` to represent operators, this PR
checks the lang item directly.
-rw-r--r--src/librustc_ast_lowering/expr.rs17
-rw-r--r--src/librustc_hir/lang_items.rs80
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs2
-rw-r--r--src/librustc_middle/lint.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs72
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs4
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mod.rs157
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs6
-rw-r--r--src/librustc_mir/transform/const_prop.rs1
-rw-r--r--src/librustc_passes/lang_items.rs6
-rw-r--r--src/librustc_span/hygiene.rs11
-rw-r--r--src/librustc_span/lib.rs3
-rw-r--r--src/test/ui/binop/binop-consume-args.stderr70
-rw-r--r--src/test/ui/binop/binop-move-semantics.stderr21
-rw-r--r--src/test/ui/borrowck/borrowck-unboxed-closures.stderr7
-rw-r--r--src/test/ui/closure_context/issue-42065.stderr7
-rw-r--r--src/test/ui/codemap_tests/tab_3.stderr8
-rw-r--r--src/test/ui/issues/issue-12127.stderr7
-rw-r--r--src/test/ui/issues/issue-33941.rs1
-rw-r--r--src/test/ui/issues/issue-33941.stderr12
-rw-r--r--src/test/ui/issues/issue-34721.stderr9
-rw-r--r--src/test/ui/issues/issue-61108.stderr8
-rw-r--r--src/test/ui/issues/issue-64559.stderr8
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.rs74
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.stderr158
-rw-r--r--src/test/ui/moves/moves-based-on-type-access-to-field.stderr8
-rw-r--r--src/test/ui/moves/moves-based-on-type-exprs.stderr16
-rw-r--r--src/test/ui/once-cant-call-twice-on-heap.stderr7
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr7
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr7
-rw-r--r--src/test/ui/unop-move-semantics.stderr7
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.stderr8
-rw-r--r--src/test/ui/unsized-locals/double-move.stderr8
-rw-r--r--src/test/ui/use/use-after-move-self-based-on-type.stderr8
-rw-r--r--src/test/ui/use/use-after-move-self.stderr8
-rw-r--r--src/test/ui/walk-struct-literal-with.stderr8
38 files changed, 745 insertions, 102 deletions
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index d2c4478ccfe..90a3a5ec64e 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
+use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_target::asm;
 use std::collections::hash_map::Entry;
@@ -1361,9 +1361,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Block,
         opt_label: Option<Label>,
     ) -> hir::Expr<'hir> {
+        let orig_head_span = head.span;
         // expand <head>
         let mut head = self.lower_expr_mut(head);
-        let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
+        let desugared_span = self.mark_span_with_reason(
+            DesugaringKind::ForLoop(ForLoopLoc::Head),
+            orig_head_span,
+            None,
+        );
         head.span = desugared_span;
 
         let iter = Ident::with_dummy_span(sym::iter);
@@ -1458,10 +1463,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `mut iter => { ... }`
         let iter_arm = self.arm(iter_pat, loop_expr);
 
+        let into_iter_span = self.mark_span_with_reason(
+            DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
+            orig_head_span,
+            None,
+        );
+
         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
         let into_iter_expr = {
             let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
-            self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head])
+            self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
         };
 
         let match_expr = self.arena.alloc(self.expr_match(
diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs
index cd6f034f7a5..5aaf219b315 100644
--- a/src/librustc_hir/lang_items.rs
+++ b/src/librustc_hir/lang_items.rs
@@ -21,11 +21,26 @@ use rustc_span::Span;
 
 use lazy_static::lazy_static;
 
+pub enum LangItemGroup {
+    Op,
+}
+
+const NUM_GROUPS: usize = 1;
+
+macro_rules! expand_group {
+    () => {
+        None
+    };
+    ($group:expr) => {
+        Some($group)
+    };
+}
+
 // The actual lang items defined come at the end of this file in one handy table.
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
     (
-        $( $variant:ident, $name:expr, $method:ident, $target:expr; )*
+        $( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
     ) => {
 
         enum_from_u32! {
@@ -45,6 +60,13 @@ macro_rules! language_item_table {
                     $( $variant => $name, )*
                 }
             }
+
+            pub fn group(self) -> Option<LangItemGroup> {
+                use LangItemGroup::*;
+                match self {
+                    $( $variant => expand_group!($($group)*), )*
+                }
+            }
         }
 
         #[derive(HashStable_Generic)]
@@ -54,6 +76,9 @@ macro_rules! language_item_table {
             pub items: Vec<Option<DefId>>,
             /// Lang items that were not found during collection.
             pub missing: Vec<LangItem>,
+            /// Mapping from `LangItemGroup` discriminants to all
+            /// `DefId`s of lang items in that group.
+            pub groups: [Vec<DefId>; NUM_GROUPS],
         }
 
         impl LanguageItems {
@@ -64,6 +89,7 @@ macro_rules! language_item_table {
                 Self {
                     items: vec![$(init_none($variant)),*],
                     missing: Vec::new(),
+                    groups: [vec![]; NUM_GROUPS],
                 }
             }
 
@@ -79,6 +105,10 @@ macro_rules! language_item_table {
                 self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
             }
 
+            pub fn group(&self, group: LangItemGroup) -> &[DefId] {
+                self.groups[group as usize].as_ref()
+            }
+
             $(
                 /// Returns the corresponding `DefId` for the lang item
                 #[doc = $name]
@@ -171,30 +201,30 @@ language_item_table! {
     CoerceUnsizedTraitLangItem,  "coerce_unsized",     coerce_unsized_trait,    Target::Trait;
     DispatchFromDynTraitLangItem,"dispatch_from_dyn",  dispatch_from_dyn_trait, Target::Trait;
 
-    AddTraitLangItem,            "add",                add_trait,               Target::Trait;
-    SubTraitLangItem,            "sub",                sub_trait,               Target::Trait;
-    MulTraitLangItem,            "mul",                mul_trait,               Target::Trait;
-    DivTraitLangItem,            "div",                div_trait,               Target::Trait;
-    RemTraitLangItem,            "rem",                rem_trait,               Target::Trait;
-    NegTraitLangItem,            "neg",                neg_trait,               Target::Trait;
-    NotTraitLangItem,            "not",                not_trait,               Target::Trait;
-    BitXorTraitLangItem,         "bitxor",             bitxor_trait,            Target::Trait;
-    BitAndTraitLangItem,         "bitand",             bitand_trait,            Target::Trait;
-    BitOrTraitLangItem,          "bitor",              bitor_trait,             Target::Trait;
-    ShlTraitLangItem,            "shl",                shl_trait,               Target::Trait;
-    ShrTraitLangItem,            "shr",                shr_trait,               Target::Trait;
-    AddAssignTraitLangItem,      "add_assign",         add_assign_trait,        Target::Trait;
-    SubAssignTraitLangItem,      "sub_assign",         sub_assign_trait,        Target::Trait;
-    MulAssignTraitLangItem,      "mul_assign",         mul_assign_trait,        Target::Trait;
-    DivAssignTraitLangItem,      "div_assign",         div_assign_trait,        Target::Trait;
-    RemAssignTraitLangItem,      "rem_assign",         rem_assign_trait,        Target::Trait;
-    BitXorAssignTraitLangItem,   "bitxor_assign",      bitxor_assign_trait,     Target::Trait;
-    BitAndAssignTraitLangItem,   "bitand_assign",      bitand_assign_trait,     Target::Trait;
-    BitOrAssignTraitLangItem,    "bitor_assign",       bitor_assign_trait,      Target::Trait;
-    ShlAssignTraitLangItem,      "shl_assign",         shl_assign_trait,        Target::Trait;
-    ShrAssignTraitLangItem,      "shr_assign",         shr_assign_trait,        Target::Trait;
-    IndexTraitLangItem,          "index",              index_trait,             Target::Trait;
-    IndexMutTraitLangItem,       "index_mut",          index_mut_trait,         Target::Trait;
+    AddTraitLangItem(Op),        "add",                add_trait,               Target::Trait;
+    SubTraitLangItem(Op),        "sub",                sub_trait,               Target::Trait;
+    MulTraitLangItem(Op),        "mul",                mul_trait,               Target::Trait;
+    DivTraitLangItem(Op),        "div",                div_trait,               Target::Trait;
+    RemTraitLangItem(Op),        "rem",                rem_trait,               Target::Trait;
+    NegTraitLangItem(Op),        "neg",                neg_trait,               Target::Trait;
+    NotTraitLangItem(Op),        "not",                not_trait,               Target::Trait;
+    BitXorTraitLangItem(Op),     "bitxor",             bitxor_trait,            Target::Trait;
+    BitAndTraitLangItem(Op),     "bitand",             bitand_trait,            Target::Trait;
+    BitOrTraitLangItem(Op),      "bitor",              bitor_trait,             Target::Trait;
+    ShlTraitLangItem(Op),        "shl",                shl_trait,               Target::Trait;
+    ShrTraitLangItem(Op),        "shr",                shr_trait,               Target::Trait;
+    AddAssignTraitLangItem(Op),  "add_assign",         add_assign_trait,        Target::Trait;
+    SubAssignTraitLangItem(Op),  "sub_assign",         sub_assign_trait,        Target::Trait;
+    MulAssignTraitLangItem(Op),  "mul_assign",         mul_assign_trait,        Target::Trait;
+    DivAssignTraitLangItem(Op),  "div_assign",         div_assign_trait,        Target::Trait;
+    RemAssignTraitLangItem(Op),  "rem_assign",         rem_assign_trait,        Target::Trait;
+    BitXorAssignTraitLangItem(Op),"bitxor_assign",     bitxor_assign_trait,     Target::Trait;
+    BitAndAssignTraitLangItem(Op),"bitand_assign",     bitand_assign_trait,     Target::Trait;
+    BitOrAssignTraitLangItem(Op),"bitor_assign",       bitor_assign_trait,      Target::Trait;
+    ShlAssignTraitLangItem(Op),  "shl_assign",         shl_assign_trait,        Target::Trait;
+    ShrAssignTraitLangItem(Op),  "shr_assign",         shr_assign_trait,        Target::Trait;
+    IndexTraitLangItem(Op),      "index",              index_trait,             Target::Trait;
+    IndexMutTraitLangItem(Op),   "index_mut",          index_mut_trait,         Target::Trait;
 
     UnsafeCellTypeLangItem,      "unsafe_cell",        unsafe_cell_type,        Target::Struct;
     VaListTypeLangItem,          "va_list",            va_list,                 Target::Struct;
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index 04d941fb8a7..1687bcc1556 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let msg = if let Some(simple_ident) = pattern.simple_ident() {
                 match pattern.span.desugaring_kind() {
                     None => format!("consider giving `{}` {}", simple_ident, suffix),
-                    Some(DesugaringKind::ForLoop) => {
+                    Some(DesugaringKind::ForLoop(_)) => {
                         "the element type for this iterator is not specified".to_string()
                     }
                     _ => format!("this needs {}", suffix),
diff --git a/src/librustc_middle/lint.rs b/src/librustc_middle/lint.rs
index 27239b4ad2e..bb62c1bb824 100644
--- a/src/librustc_middle/lint.rs
+++ b/src/librustc_middle/lint.rs
@@ -339,7 +339,7 @@ pub fn struct_lint_level<'s, 'd>(
 pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     let expn_data = span.ctxt().outer_expn_data();
     match expn_data.kind {
-        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
+        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false,
         ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
         ExpnKind::Macro(MacroKind::Bang, _) => {
             // Dummy span for the `def_site` means it's an external macro.
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 60a1fe0b198..e85f69554d0 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -24,7 +24,8 @@ use crate::borrow_check::{
 };
 
 use super::{
-    explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+    explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
+    RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -150,11 +151,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         format!("value moved{} here, in previous iteration of loop", move_msg),
                     );
                 } else {
-                    err.span_label(move_span, format!("value moved{} here", move_msg));
-                    move_spans.var_span_label(
-                        &mut err,
-                        format!("variable moved due to use{}", move_spans.describe()),
-                    );
+                    if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
+                        move_spans
+                    {
+                        let place_name = self
+                            .describe_place(moved_place.as_ref())
+                            .map(|n| format!("`{}`", n))
+                            .unwrap_or_else(|| "value".to_owned());
+                        match kind {
+                            FnSelfUseKind::FnOnceCall => {
+                                err.span_label(
+                                    fn_call_span,
+                                    &format!("{} moved due to this call", place_name),
+                                );
+                                err.span_note(
+                                    var_span,
+                                    "this value implements `FnOnce`, which causes it to be moved when called",
+                                );
+                            }
+                            FnSelfUseKind::Operator { self_arg } => {
+                                err.span_label(
+                                    fn_call_span,
+                                    &format!("{} moved due to usage in operator", place_name),
+                                );
+                                if self.fn_self_span_reported.insert(fn_span) {
+                                    err.span_note(
+                                        self_arg.span,
+                                        "calling this operator moves the left-hand side",
+                                    );
+                                }
+                            }
+                            FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
+                                if implicit_into_iter {
+                                    err.span_label(
+                                        fn_call_span,
+                                        &format!(
+                                            "{} moved due to this implicit call to `.into_iter()`",
+                                            place_name
+                                        ),
+                                    );
+                                } else {
+                                    err.span_label(
+                                        fn_call_span,
+                                        &format!("{} moved due to this method call", place_name),
+                                    );
+                                }
+                                // Avoid pointing to the same function in multiple different
+                                // error messages
+                                if self.fn_self_span_reported.insert(self_arg.span) {
+                                    err.span_note(
+                                        self_arg.span,
+                                        &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
+                                    );
+                                }
+                            }
+                        }
+                    } else {
+                        err.span_label(move_span, format!("value moved{} here", move_msg));
+                        move_spans.var_span_label(
+                            &mut err,
+                            format!("variable moved due to use{}", move_spans.describe()),
+                        );
+                    }
                 }
                 if let UseSpans::PatUse(span) = move_spans {
                     err.span_suggestion_verbose(
@@ -170,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     );
                 }
 
-                if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
+                if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
                     let sess = self.infcx.tcx.sess;
                     if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
                         err.span_suggestion(
diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 849fd63998d..b591b938b5a 100644
--- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -509,7 +509,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // Used in a closure.
                 (LaterUseKind::ClosureCapture, var_span)
             }
-            UseSpans::PatUse(span) | UseSpans::OtherUse(span) => {
+            UseSpans::PatUse(span)
+            | UseSpans::OtherUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. } => {
                 let block = &self.body.basic_blocks()[location.block];
 
                 let kind = if let Some(&Statement {
diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
index 388076a9d60..e94952e1c54 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -4,6 +4,7 @@ use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
 use rustc_hir::GeneratorKind;
 use rustc_middle::mir::{
     AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
@@ -11,7 +12,11 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::{
+    hygiene::{DesugaringKind, ForLoopLoc},
+    symbol::sym,
+    Span,
+};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
@@ -33,6 +38,7 @@ crate use mutability_errors::AccessKind;
 crate use outlives_suggestion::OutlivesSuggestionBuilder;
 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
 crate use region_name::{RegionName, RegionNameSource};
+use rustc_span::symbol::Ident;
 
 pub(super) struct IncludingDowncast(pub(super) bool);
 
@@ -529,18 +535,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 }
 
-// The span(s) associated to a use of a place.
+/// The span(s) associated to a use of a place.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub(super) enum UseSpans {
-    // The access is caused by capturing a variable for a closure.
+    /// The access is caused by capturing a variable for a closure.
     ClosureUse {
-        // This is true if the captured variable was from a generator.
+        /// This is true if the captured variable was from a generator.
         generator_kind: Option<GeneratorKind>,
-        // The span of the args of the closure, including the `move` keyword if
-        // it's present.
+        /// The span of the args of the closure, including the `move` keyword if
+        /// it's present.
         args_span: Span,
-        // The span of the first use of the captured variable inside the closure.
+        /// The span of the first use of the captured variable inside the closure.
+        var_span: Span,
+    },
+    /// The access is caused by using a variable as the receiver of a method
+    /// that takes 'self'
+    FnSelfUse {
+        /// The span of the variable being moved
         var_span: Span,
+        /// The span of the method call on the variable
+        fn_call_span: Span,
+        /// The definition span of the method being called
+        fn_span: Span,
+        kind: FnSelfUseKind,
     },
     /// This access is caused by a `match` or `if let` pattern.
     PatUse(Span),
@@ -548,11 +565,22 @@ pub(super) enum UseSpans {
     OtherUse(Span),
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub(super) enum FnSelfUseKind {
+    /// A normal method call of the form `receiver.foo(a, b, c)`
+    Normal { self_arg: Ident, implicit_into_iter: bool },
+    /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
+    FnOnceCall,
+    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
+    Operator { self_arg: Ident },
+}
+
 impl UseSpans {
     pub(super) fn args_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { args_span: span, .. }
             | UseSpans::PatUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
         }
     }
@@ -561,6 +589,7 @@ impl UseSpans {
         match self {
             UseSpans::ClosureUse { var_span: span, .. }
             | UseSpans::PatUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
         }
     }
@@ -631,6 +660,7 @@ impl UseSpans {
         match self {
             closure @ UseSpans::ClosureUse { .. } => closure,
             UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
+            fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
         }
     }
 }
@@ -733,25 +763,112 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
         if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
-            let def_id = match kind {
+            match kind {
                 box AggregateKind::Closure(def_id, _)
-                | box AggregateKind::Generator(def_id, _, _) => def_id,
-                _ => return OtherUse(stmt.source_info.span),
+                | box AggregateKind::Generator(def_id, _, _) => {
+                    debug!("move_spans: def_id={:?} places={:?}", def_id, places);
+                    if let Some((args_span, generator_kind, var_span)) =
+                        self.closure_span(*def_id, moved_place, places)
+                    {
+                        return ClosureUse { generator_kind, args_span, var_span };
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        let normal_ret =
+            if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
+                PatUse(stmt.source_info.span)
+            } else {
+                OtherUse(stmt.source_info.span)
             };
 
-            debug!("move_spans: def_id={:?} places={:?}", def_id, places);
-            if let Some((args_span, generator_kind, var_span)) =
-                self.closure_span(*def_id, moved_place, places)
-            {
-                return ClosureUse { generator_kind, args_span, var_span };
+        // We are trying to find MIR of the form:
+        // ```
+        // _temp = _moved_val;
+        // ...
+        // FnSelfCall(_temp, ...)
+        // ```
+        //
+        // where `_moved_val` is the place we generated the move error for,
+        // `_temp` is some other local, and `FnSelfCall` is a function
+        // that has a `self` parameter.
+
+        let target_temp = match stmt.kind {
+            StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
+                temp.as_local().unwrap()
             }
-        }
+            _ => return normal_ret,
+        };
 
-        if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
-            PatUse(stmt.source_info.span)
-        } else {
-            OtherUse(stmt.source_info.span)
+        debug!("move_spans: target_temp = {:?}", target_temp);
+
+        if let Some(Terminator {
+            kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. },
+            ..
+        }) = &self.body[location.block].terminator
+        {
+            let mut method_did = None;
+            if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
+                if let ty::FnDef(def_id, _) = ty.kind {
+                    debug!("move_spans: fn = {:?}", def_id);
+                    if let Some(ty::AssocItem { fn_has_self_parameter, .. }) =
+                        self.infcx.tcx.opt_associated_item(def_id)
+                    {
+                        if *fn_has_self_parameter {
+                            method_did = Some(def_id);
+                        }
+                    }
+                }
+            }
+
+            let tcx = self.infcx.tcx;
+            let method_did = if let Some(did) = method_did { did } else { return normal_ret };
+
+            if let [Operand::Move(self_place), ..] = **args {
+                if self_place.as_local() == Some(target_temp) {
+                    let parent = tcx.parent(method_did);
+                    let is_fn_once = parent == tcx.lang_items().fn_once_trait();
+                    let is_operator = !from_hir_call
+                        && parent.map_or(false, |p| {
+                            tcx.lang_items().group(LangItemGroup::Op).contains(&p)
+                        });
+                    let fn_call_span = *fn_span;
+
+                    let self_arg = tcx.fn_arg_names(method_did)[0];
+
+                    let kind = if is_fn_once {
+                        FnSelfUseKind::FnOnceCall
+                    } else if is_operator {
+                        FnSelfUseKind::Operator { self_arg }
+                    } else {
+                        debug!(
+                            "move_spans: method_did={:?}, fn_call_span={:?}",
+                            method_did, fn_call_span
+                        );
+                        let implicit_into_iter = matches!(
+                            fn_call_span.desugaring_kind(),
+                            Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
+                        );
+                        FnSelfUseKind::Normal { self_arg, implicit_into_iter }
+                    };
+
+                    return FnSelfUse {
+                        var_span: stmt.source_info.span,
+                        fn_call_span,
+                        fn_span: self
+                            .infcx
+                            .tcx
+                            .sess
+                            .source_map()
+                            .guess_head_span(self.infcx.tcx.def_span(method_did)),
+                        kind,
+                    };
+                }
+            }
         }
+        return normal_ret;
     }
 
     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index b49e4187fb8..4883b08e424 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -408,7 +408,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     format!("{}.as_ref()", snippet),
                     Applicability::MaybeIncorrect,
                 );
-            } else if span.is_desugaring(DesugaringKind::ForLoop)
+            } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_)))
                 && self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id)
             {
                 // FIXME: suggest for anything that implements `IntoIterator`.
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 4d4b6fb9386..b4bc89e827d 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -365,7 +365,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                     opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
                                 match opt_desugaring_kind {
                                     // on for loops, RHS points to the iterator part
-                                    Some(DesugaringKind::ForLoop) => Some((
+                                    Some(DesugaringKind::ForLoop(_)) => Some((
                                         false,
                                         opt_assignment_rhs_span.unwrap(),
                                         format!(
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 03b663eb750..83691d439eb 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -278,6 +278,7 @@ fn do_mir_borrowck<'a, 'tcx>(
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
+                fn_self_span_reported: Default::default(),
                 locals_are_invalidated_at_exit,
                 access_place_error_reported: Default::default(),
                 reservation_error_reported: Default::default(),
@@ -311,6 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         location_table,
         movable_generator,
         locals_are_invalidated_at_exit,
+        fn_self_span_reported: Default::default(),
         access_place_error_reported: Default::default(),
         reservation_error_reported: Default::default(),
         reservation_warnings: Default::default(),
@@ -487,6 +489,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
     // but it is currently inconvenient to track down the `BorrowIndex`
     // at the time we detect and report a reservation error.
     reservation_error_reported: FxHashSet<Place<'tcx>>,
+    /// This fields keeps track of the `Span`s that we have
+    /// used to report extra information for `FnSelfUse`, to avoid
+    /// unnecessarily verbose errors.
+    fn_self_span_reported: FxHashSet<Span>,
     /// Migration warnings to be reported for #56254. We delay reporting these
     /// so that we can suppress the warning if there's a corresponding error
     /// for the activation of the borrow.
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 19337c520f9..ba538803468 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -506,6 +506,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // This is basically `force_bits`.
             let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok());
             if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
+                debug!("check_binary_op: reporting assert for {:?}", source_info);
                 self.report_assert_as_lint(
                     lint::builtin::ARITHMETIC_OVERFLOW,
                     source_info,
diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs
index f4167c8644e..0be37cb0960 100644
--- a/src/librustc_passes/lang_items.rs
+++ b/src/librustc_passes/lang_items.rs
@@ -102,7 +102,8 @@ impl LanguageItemCollector<'tcx> {
         // Check for duplicates.
         if let Some(original_def_id) = self.items.items[item_index] {
             if original_def_id != item_def_id {
-                let name = LangItem::from_u32(item_index as u32).unwrap().name();
+                let lang_item = LangItem::from_u32(item_index as u32).unwrap();
+                let name = lang_item.name();
                 let mut err = match self.tcx.hir().span_if_local(item_def_id) {
                     Some(span) => struct_span_err!(
                         self.tcx.sess,
@@ -152,6 +153,9 @@ impl LanguageItemCollector<'tcx> {
 
         // Matched.
         self.items.items[item_index] = Some(item_def_id);
+        if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
+            self.items.groups[group as usize].push(item_def_id);
+        }
     }
 }
 
diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs
index c0fb84e741f..60bbdd0495c 100644
--- a/src/librustc_span/hygiene.rs
+++ b/src/librustc_span/hygiene.rs
@@ -822,7 +822,14 @@ pub enum DesugaringKind {
     OpaqueTy,
     Async,
     Await,
-    ForLoop,
+    ForLoop(ForLoopLoc),
+}
+
+/// A location in the desugaring of a `for` loop
+#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+pub enum ForLoopLoc {
+    Head,
+    IntoIter,
 }
 
 impl DesugaringKind {
@@ -835,7 +842,7 @@ impl DesugaringKind {
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
-            DesugaringKind::ForLoop => "`for` loop",
+            DesugaringKind::ForLoop(_) => "`for` loop",
         }
     }
 }
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index 96240066834..dcd2e83b747 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -30,8 +30,9 @@ use source_map::SourceMap;
 pub mod edition;
 use edition::Edition;
 pub mod hygiene;
+pub use hygiene::SyntaxContext;
 use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext};
+pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
 pub mod def_id;
 use def_id::{CrateNum, DefId, LOCAL_CRATE};
 mod span_encoding;
diff --git a/src/test/ui/binop/binop-consume-args.stderr b/src/test/ui/binop/binop-consume-args.stderr
index acdc03e3726..addc8a0efe1 100644
--- a/src/test/ui/binop/binop-consume-args.stderr
+++ b/src/test/ui/binop/binop-consume-args.stderr
@@ -4,10 +4,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs + rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL |     fn add(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -35,10 +40,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs - rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL |     fn sub(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -66,10 +76,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs * rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL |     fn mul(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -97,10 +112,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs / rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL |     fn div(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -128,10 +148,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs % rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL |     fn rem(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -159,10 +184,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs & rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn bitand(self, rhs: Rhs) -> Self::Output;
+   |               ^^^^
 help: consider further restricting this bound
    |
 LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -190,10 +220,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                     --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs | rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn bitor(self, rhs: Rhs) -> Self::Output;
+   |              ^^^^
 help: consider further restricting this bound
    |
 LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -221,10 +256,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs ^ rhs;
-   |     --- value moved here
+   |     --------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn bitxor(self, rhs: Rhs) -> Self::Output;
+   |               ^^^^
 help: consider further restricting this bound
    |
 LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -252,10 +292,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs << rhs;
-   |     --- value moved here
+   |     ---------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn shl(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@@ -283,10 +328,15 @@ error[E0382]: use of moved value: `lhs`
 LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
    |                                 --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
 LL |     lhs >> rhs;
-   |     --- value moved here
+   |     ---------- `lhs` moved due to usage in operator
 LL |     drop(lhs);
    |          ^^^ value used here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn shr(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr
index 6d5ac9cab30..97b70efe20e 100644
--- a/src/test/ui/binop/binop-move-semantics.stderr
+++ b/src/test/ui/binop/binop-move-semantics.stderr
@@ -1,14 +1,21 @@
 error[E0382]: use of moved value: `x`
   --> $DIR/binop-move-semantics.rs:8:5
    |
-LL | fn double_move<T: Add<Output=()>>(x: T) {
-   |                                   - move occurs because `x` has type `T`, which does not implement the `Copy` trait
-LL |     x
-   |     - value moved here
-LL |     +
-LL |     x;
-   |     ^ value used here after move
+LL |   fn double_move<T: Add<Output=()>>(x: T) {
+   |                                     - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+LL | /     x
+LL | |     +
+LL | |     x;
+   | |     ^
+   | |     |
+   | |_____value used here after move
+   |       `x` moved due to usage in operator
+   |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
    |
+LL |     fn add(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn double_move<T: Add<Output=()> + Copy>(x: T) {
diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
index a51cda548ef..bc1721944fb 100644
--- a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
+++ b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
@@ -22,10 +22,15 @@ error[E0382]: use of moved value: `f`
 LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
    |                                       - move occurs because `f` has type `F`, which does not implement the `Copy` trait
 LL |     f(1, 2);
-   |     - value moved here
+   |     ------- `f` moved due to this call
 LL |     f(1, 2);
    |     ^ value used here after move
    |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/borrowck-unboxed-closures.rs:11:5
+   |
+LL |     f(1, 2);
+   |     ^
 help: consider further restricting this bound
    |
 LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) {
diff --git a/src/test/ui/closure_context/issue-42065.stderr b/src/test/ui/closure_context/issue-42065.stderr
index 69d98654048..896bb6dc6be 100644
--- a/src/test/ui/closure_context/issue-42065.stderr
+++ b/src/test/ui/closure_context/issue-42065.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `debug_dump_dict`
   --> $DIR/issue-42065.rs:11:5
    |
 LL |     debug_dump_dict();
-   |     --------------- value moved here
+   |     ----------------- `debug_dump_dict` moved due to this call
 LL |     debug_dump_dict();
    |     ^^^^^^^^^^^^^^^ value used here after move
    |
@@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `di
    |
 LL |         for (key, value) in dict {
    |                             ^^^^
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/issue-42065.rs:10:5
+   |
+LL |     debug_dump_dict();
+   |     ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr
index 97816a76004..614e69e89f6 100644
--- a/src/test/ui/codemap_tests/tab_3.stderr
+++ b/src/test/ui/codemap_tests/tab_3.stderr
@@ -4,10 +4,16 @@ error[E0382]: borrow of moved value: `some_vec`
 LL |     let some_vec = vec!["hi"];
    |         -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
 LL |     some_vec.into_iter();
-   |     -------- value moved here
+   |              ----------- `some_vec` moved due to this method call
 LL |     {
 LL |         println!("{:?}", some_vec);
    |                          ^^^^^^^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr
index 2283b1275d0..b759aa45e3e 100644
--- a/src/test/ui/issues/issue-12127.stderr
+++ b/src/test/ui/issues/issue-12127.stderr
@@ -2,10 +2,15 @@ error[E0382]: use of moved value: `f`
   --> $DIR/issue-12127.rs:11:9
    |
 LL |         f();
-   |         - value moved here
+   |         --- `f` moved due to this call
 LL |         f();
    |         ^ value used here after move
    |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/issue-12127.rs:10:9
+   |
+LL |         f();
+   |         ^
    = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:std::boxed::Box<isize>]`, which does not implement the `Copy` trait
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs
index ccaa6334856..4fb805b37e0 100644
--- a/src/test/ui/issues/issue-33941.rs
+++ b/src/test/ui/issues/issue-33941.rs
@@ -3,4 +3,5 @@ use std::collections::HashMap;
 fn main() {
     for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
     //~^ ERROR type mismatch
+    //~| ERROR type mismatch
 }
diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr
index 734ae78f362..20335d2cdd6 100644
--- a/src/test/ui/issues/issue-33941.stderr
+++ b/src/test/ui/issues/issue-33941.stderr
@@ -17,6 +17,16 @@ LL |     for _ in HashMap::new().iter().cloned() {}
            found reference `&_`
    = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>`
 
-error: aborting due to 2 previous errors
+error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_`
+  --> $DIR/issue-33941.rs:4:14
+   |
+LL |     for _ in HashMap::new().iter().cloned() {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
+   |
+   = note:  expected tuple `(&_, &_)`
+           found reference `&_`
+   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned<std::collections::hash_map::Iter<'_, _, _>>`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr
index 6cfed20f43a..b4cc1a0aa7e 100644
--- a/src/test/ui/issues/issue-34721.stderr
+++ b/src/test/ui/issues/issue-34721.stderr
@@ -5,14 +5,19 @@ LL |     pub fn baz<T: Foo>(x: T) -> T {
    |                        - move occurs because `x` has type `T`, which does not implement the `Copy` trait
 LL |         if 0 == 1 {
 LL |             bar::bar(x.zero())
-   |                      - value moved here
+   |                        ------ `x` moved due to this method call
 LL |         } else {
 LL |             x.zero()
-   |             - value moved here
+   |               ------ `x` moved due to this method call
 LL |         };
 LL |         x.zero()
    |         ^ value used here after move
    |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $DIR/issue-34721.rs:4:13
+   |
+LL |     fn zero(self) -> Self;
+   |             ^^^^
 help: consider further restricting this bound
    |
 LL |     pub fn baz<T: Foo + Copy>(x: T) -> T {
diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr
index 8523a6f6548..ba43f2d33ee 100644
--- a/src/test/ui/issues/issue-61108.stderr
+++ b/src/test/ui/issues/issue-61108.stderr
@@ -6,11 +6,17 @@ LL |     let mut bad_letters = vec!['e', 't', 'o', 'i'];
 LL |     for l in bad_letters {
    |              -----------
    |              |
-   |              value moved here
+   |              `bad_letters` moved due to this implicit call to `.into_iter()`
    |              help: consider borrowing to avoid moving into the for loop: `&bad_letters`
 ...
 LL |     bad_letters.push('s');
    |     ^^^^^^^^^^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr
index 3c685dc8d08..2c337bae130 100644
--- a/src/test/ui/issues/issue-64559.stderr
+++ b/src/test/ui/issues/issue-64559.stderr
@@ -6,12 +6,18 @@ LL |     let orig = vec![true];
 LL |     for _val in orig {}
    |                 ----
    |                 |
-   |                 value moved here
+   |                 `orig` moved due to this implicit call to `.into_iter()`
    |                 help: consider borrowing to avoid moving into the for loop: `&orig`
 LL |     let _closure = || orig;
    |                    ^^ ---- use occurs due to use in closure
    |                    |
    |                    value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `orig`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-fn-self-receiver.rs b/src/test/ui/moves/move-fn-self-receiver.rs
new file mode 100644
index 00000000000..6107f53fa19
--- /dev/null
+++ b/src/test/ui/moves/move-fn-self-receiver.rs
@@ -0,0 +1,74 @@
+use std::pin::Pin;
+use std::rc::Rc;
+use std::ops::Add;
+
+struct Foo;
+
+impl Add for Foo {
+    type Output = ();
+    fn add(self, _rhs: Self) -> () {}
+}
+
+impl Foo {
+    fn use_self(self) {}
+    fn use_box_self(self: Box<Self>) {}
+    fn use_pin_box_self(self: Pin<Box<Self>>) {}
+    fn use_rc_self(self: Rc<Self>) {}
+    fn use_mut_self(&mut self) -> &mut Self { self }
+}
+
+struct Container(Vec<bool>);
+
+impl Container {
+    fn custom_into_iter(self) -> impl Iterator<Item = bool> {
+        self.0.into_iter()
+    }
+}
+
+fn move_out(val: Container) {
+    val.0.into_iter().next();
+    val.0; //~ ERROR use of moved
+
+    let foo = Foo;
+    foo.use_self();
+    foo; //~ ERROR use of moved
+
+    let second_foo = Foo;
+    second_foo.use_self();
+    second_foo; //~ ERROR use of moved
+
+    let boxed_foo = Box::new(Foo);
+    boxed_foo.use_box_self();
+    boxed_foo; //~ ERROR use of moved
+
+    let pin_box_foo = Box::pin(Foo);
+    pin_box_foo.use_pin_box_self();
+    pin_box_foo; //~ ERROR use of moved
+
+    let mut mut_foo = Foo;
+    let ret = mut_foo.use_mut_self();
+    mut_foo; //~ ERROR cannot move out
+    ret;
+
+    let rc_foo = Rc::new(Foo);
+    rc_foo.use_rc_self();
+    rc_foo; //~ ERROR use of moved
+
+    let foo_add = Foo;
+    foo_add + Foo;
+    foo_add; //~ ERROR use of moved
+
+    let implicit_into_iter = vec![true];
+    for _val in implicit_into_iter {}
+    implicit_into_iter; //~ ERROR use of moved
+
+    let explicit_into_iter = vec![true];
+    for _val in explicit_into_iter.into_iter() {}
+    explicit_into_iter; //~ ERROR use of moved
+
+    let container = Container(vec![]);
+    for _val in container.custom_into_iter() {}
+    container; //~ ERROR use of moved
+}
+
+fn main() {}
diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr
new file mode 100644
index 00000000000..4333e8a23e8
--- /dev/null
+++ b/src/test/ui/moves/move-fn-self-receiver.stderr
@@ -0,0 +1,158 @@
+error[E0382]: use of moved value: `val.0`
+  --> $DIR/move-fn-self-receiver.rs:30:5
+   |
+LL |     val.0.into_iter().next();
+   |           ----------- `val.0` moved due to this method call
+LL |     val.0;
+   |     ^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
+   = note: move occurs because `val.0` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/move-fn-self-receiver.rs:34:5
+   |
+LL |     let foo = Foo;
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo.use_self();
+   |         ---------- `foo` moved due to this method call
+LL |     foo;
+   |     ^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `foo`
+  --> $DIR/move-fn-self-receiver.rs:13:17
+   |
+LL |     fn use_self(self) {}
+   |                 ^^^^
+
+error[E0382]: use of moved value: `second_foo`
+  --> $DIR/move-fn-self-receiver.rs:38:5
+   |
+LL |     let second_foo = Foo;
+   |         ---------- move occurs because `second_foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     second_foo.use_self();
+   |                ---------- `second_foo` moved due to this method call
+LL |     second_foo;
+   |     ^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `boxed_foo`
+  --> $DIR/move-fn-self-receiver.rs:42:5
+   |
+LL |     let boxed_foo = Box::new(Foo);
+   |         --------- move occurs because `boxed_foo` has type `std::boxed::Box<Foo>`, which does not implement the `Copy` trait
+LL |     boxed_foo.use_box_self();
+   |               -------------- `boxed_foo` moved due to this method call
+LL |     boxed_foo;
+   |     ^^^^^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo`
+  --> $DIR/move-fn-self-receiver.rs:14:21
+   |
+LL |     fn use_box_self(self: Box<Self>) {}
+   |                     ^^^^
+
+error[E0382]: use of moved value: `pin_box_foo`
+  --> $DIR/move-fn-self-receiver.rs:46:5
+   |
+LL |     let pin_box_foo = Box::pin(Foo);
+   |         ----------- move occurs because `pin_box_foo` has type `std::pin::Pin<std::boxed::Box<Foo>>`, which does not implement the `Copy` trait
+LL |     pin_box_foo.use_pin_box_self();
+   |                 ------------------ `pin_box_foo` moved due to this method call
+LL |     pin_box_foo;
+   |     ^^^^^^^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo`
+  --> $DIR/move-fn-self-receiver.rs:15:25
+   |
+LL |     fn use_pin_box_self(self: Pin<Box<Self>>) {}
+   |                         ^^^^
+
+error[E0505]: cannot move out of `mut_foo` because it is borrowed
+  --> $DIR/move-fn-self-receiver.rs:50:5
+   |
+LL |     let ret = mut_foo.use_mut_self();
+   |               ------- borrow of `mut_foo` occurs here
+LL |     mut_foo;
+   |     ^^^^^^^ move out of `mut_foo` occurs here
+LL |     ret;
+   |     --- borrow later used here
+
+error[E0382]: use of moved value: `rc_foo`
+  --> $DIR/move-fn-self-receiver.rs:55:5
+   |
+LL |     let rc_foo = Rc::new(Foo);
+   |         ------ move occurs because `rc_foo` has type `std::rc::Rc<Foo>`, which does not implement the `Copy` trait
+LL |     rc_foo.use_rc_self();
+   |            ------------- `rc_foo` moved due to this method call
+LL |     rc_foo;
+   |     ^^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo`
+  --> $DIR/move-fn-self-receiver.rs:16:20
+   |
+LL |     fn use_rc_self(self: Rc<Self>) {}
+   |                    ^^^^
+
+error[E0382]: use of moved value: `foo_add`
+  --> $DIR/move-fn-self-receiver.rs:59:5
+   |
+LL |     let foo_add = Foo;
+   |         ------- move occurs because `foo_add` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_add + Foo;
+   |     ------------- `foo_add` moved due to usage in operator
+LL |     foo_add;
+   |     ^^^^^^^ value used here after move
+   |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
+   |
+LL |     fn add(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
+
+error[E0382]: use of moved value: `implicit_into_iter`
+  --> $DIR/move-fn-self-receiver.rs:63:5
+   |
+LL |     let implicit_into_iter = vec![true];
+   |         ------------------ move occurs because `implicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+LL |     for _val in implicit_into_iter {}
+   |                 ------------------
+   |                 |
+   |                 `implicit_into_iter` moved due to this implicit call to `.into_iter()`
+   |                 help: consider borrowing to avoid moving into the for loop: `&implicit_into_iter`
+LL |     implicit_into_iter;
+   |     ^^^^^^^^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `explicit_into_iter`
+  --> $DIR/move-fn-self-receiver.rs:67:5
+   |
+LL |     let explicit_into_iter = vec![true];
+   |         ------------------ move occurs because `explicit_into_iter` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+LL |     for _val in explicit_into_iter.into_iter() {}
+   |                                    ----------- `explicit_into_iter` moved due to this method call
+LL |     explicit_into_iter;
+   |     ^^^^^^^^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `container`
+  --> $DIR/move-fn-self-receiver.rs:71:5
+   |
+LL |     let container = Container(vec![]);
+   |         --------- move occurs because `container` has type `Container`, which does not implement the `Copy` trait
+LL |     for _val in container.custom_into_iter() {}
+   |                           ------------------ `container` moved due to this method call
+LL |     container;
+   |     ^^^^^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `container`
+  --> $DIR/move-fn-self-receiver.rs:23:25
+   |
+LL |     fn custom_into_iter(self) -> impl Iterator<Item = bool> {
+   |                         ^^^^
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0382, E0505.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
index 71a3c4506ea..142feb280d1 100644
--- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
+++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
@@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `x`
 LL |     let x = vec!["hi".to_string()];
    |         - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
 LL |     consume(x.into_iter().next().unwrap());
-   |             - value moved here
+   |               ----------- `x` moved due to this method call
 LL |     touch(&x[0]);
    |            ^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr
index 67fae606c4e..ff98aab50c9 100644
--- a/src/test/ui/moves/moves-based-on-type-exprs.stderr
+++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr
@@ -104,9 +104,15 @@ error[E0382]: borrow of moved value: `x`
 LL |     let x = vec!["hi".to_string()];
    |         - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
 LL |     let _y = x.into_iter().next().unwrap();
-   |              - value moved here
+   |                ----------- `x` moved due to this method call
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:83:11
@@ -114,9 +120,15 @@ error[E0382]: borrow of moved value: `x`
 LL |     let x = vec!["hi".to_string()];
    |         - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
 LL |     let _y = [x.into_iter().next().unwrap(); 1];
-   |               - value moved here
+   |                 ----------- `x` moved due to this method call
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/once-cant-call-twice-on-heap.stderr b/src/test/ui/once-cant-call-twice-on-heap.stderr
index 7133a32431a..8761b5261d5 100644
--- a/src/test/ui/once-cant-call-twice-on-heap.stderr
+++ b/src/test/ui/once-cant-call-twice-on-heap.stderr
@@ -4,10 +4,15 @@ error[E0382]: use of moved value: `blk`
 LL | fn foo<F:FnOnce()>(blk: F) {
    |                    --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
 LL |     blk();
-   |     --- value moved here
+   |     ----- `blk` moved due to this call
 LL |     blk();
    |     ^^^ value used here after move
    |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/once-cant-call-twice-on-heap.rs:8:5
+   |
+LL |     blk();
+   |     ^^^
 help: consider further restricting this bound
    |
 LL | fn foo<F:FnOnce() + Copy>(blk: F) {
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr
index 0b9aa61a765..ab6f0651846 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick`
   --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:10:5
    |
 LL |     tick();
-   |     ---- value moved here
+   |     ------ `tick` moved due to this call
 LL |     tick();
    |     ^^^^ value used here after move
    |
@@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co
    |
 LL |     let tick = || mem::drop(counter);
    |                             ^^^^^^^
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/unboxed-closures-infer-fnonce-call-twice.rs:9:5
+   |
+LL |     tick();
+   |     ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr
index 20773d561f9..8d70a2b1760 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `tick`
   --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:10:5
    |
 LL |     tick();
-   |     ---- value moved here
+   |     ------ `tick` moved due to this call
 LL |     tick();
    |     ^^^^ value used here after move
    |
@@ -11,6 +11,11 @@ note: closure cannot be invoked more than once because it moves the variable `co
    |
 LL |     let tick = move || mem::drop(counter);
    |                                  ^^^^^^^
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/unboxed-closures-infer-fnonce-move-call-twice.rs:9:5
+   |
+LL |     tick();
+   |     ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr
index e0499cfe95c..dd54c222f64 100644
--- a/src/test/ui/unop-move-semantics.stderr
+++ b/src/test/ui/unop-move-semantics.stderr
@@ -4,11 +4,16 @@ error[E0382]: borrow of moved value: `x`
 LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
    |                                               - move occurs because `x` has type `T`, which does not implement the `Copy` trait
 LL |     !x;
-   |      - value moved here
+   |     -- `x` moved due to usage in operator
 LL | 
 LL |     x.clone();
    |     ^ value borrowed here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn not(self) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr
index 110edab69be..906b543e421 100644
--- a/src/test/ui/unsized-locals/borrow-after-move.stderr
+++ b/src/test/ui/unsized-locals/borrow-after-move.stderr
@@ -37,10 +37,16 @@ error[E0382]: borrow of moved value: `y`
 LL |         let y = *x;
    |             - move occurs because `y` has type `str`, which does not implement the `Copy` trait
 LL |         y.foo();
-   |         - value moved here
+   |           ----- `y` moved due to this method call
 ...
 LL |         println!("{}", &y);
    |                        ^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
+  --> $DIR/borrow-after-move.rs:4:12
+   |
+LL |     fn foo(self) -> String;
+   |            ^^^^
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/borrow-after-move.rs:39:24
diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr
index 5b936fb6447..49b2031c6b9 100644
--- a/src/test/ui/unsized-locals/double-move.stderr
+++ b/src/test/ui/unsized-locals/double-move.stderr
@@ -34,9 +34,15 @@ error[E0382]: use of moved value: `y`
 LL |         let y = *x;
    |             - move occurs because `y` has type `str`, which does not implement the `Copy` trait
 LL |         y.foo();
-   |         - value moved here
+   |           ----- `y` moved due to this method call
 LL |         y.foo();
    |         ^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
+  --> $DIR/double-move.rs:4:12
+   |
+LL |     fn foo(self) -> String;
+   |            ^^^^
 
 error[E0382]: use of moved value: `x`
   --> $DIR/double-move.rs:45:9
diff --git a/src/test/ui/use/use-after-move-self-based-on-type.stderr b/src/test/ui/use/use-after-move-self-based-on-type.stderr
index 9bf1175430c..b9440f4de07 100644
--- a/src/test/ui/use/use-after-move-self-based-on-type.stderr
+++ b/src/test/ui/use/use-after-move-self-based-on-type.stderr
@@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self`
 LL |     pub fn foo(self) -> isize {
    |                ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
 LL |         self.bar();
-   |         ---- value moved here
+   |              ----- `self` moved due to this method call
 LL |         return self.x;
    |                ^^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
+  --> $DIR/use-after-move-self-based-on-type.rs:15:16
+   |
+LL |     pub fn bar(self) {}
+   |                ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/use/use-after-move-self.stderr b/src/test/ui/use/use-after-move-self.stderr
index 3be0a65550b..3da53b024db 100644
--- a/src/test/ui/use/use-after-move-self.stderr
+++ b/src/test/ui/use/use-after-move-self.stderr
@@ -4,9 +4,15 @@ error[E0382]: use of moved value: `self`
 LL |     pub fn foo(self) -> isize {
    |                ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
 LL |         self.bar();
-   |         ---- value moved here
+   |              ----- `self` moved due to this method call
 LL |         return *self.x;
    |                ^^^^^^^ value used here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
+  --> $DIR/use-after-move-self.rs:13:16
+   |
+LL |     pub fn bar(self) {}
+   |                ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/walk-struct-literal-with.stderr b/src/test/ui/walk-struct-literal-with.stderr
index eeb594a21f3..ece63a2b819 100644
--- a/src/test/ui/walk-struct-literal-with.stderr
+++ b/src/test/ui/walk-struct-literal-with.stderr
@@ -4,9 +4,15 @@ error[E0382]: borrow of moved value: `start`
 LL |     let start = Mine{test:"Foo".to_string(), other_val:0};
    |         ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait
 LL |     let end = Mine{other_val:1, ..start.make_string_bar()};
-   |                                   ----- value moved here
+   |                                         ----------------- `start` moved due to this method call
 LL |     println!("{}", start.test);
    |                    ^^^^^^^^^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `start`
+  --> $DIR/walk-struct-literal-with.rs:7:28
+   |
+LL |     fn make_string_bar(mut self) -> Mine{
+   |                            ^^^^
 
 error: aborting due to previous error