about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/liballoc/vec.rs10
-rw-r--r--src/libcore/future/mod.rs1
-rw-r--r--src/libcore/iter/traits/iterator.rs4
-rw-r--r--src/libcore/str/pattern.rs20
-rw-r--r--src/librustc_ast_lowering/expr.rs24
-rw-r--r--src/librustc_error_codes/error_codes/E0446.md32
-rw-r--r--src/librustc_error_codes/error_codes/E0493.md12
-rw-r--r--src/librustc_feature/active.rs3
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs2
-rw-r--r--src/librustc_interface/passes.rs6
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs4
-rw-r--r--src/librustc_metadata/rmeta/encoder.rs16
-rw-r--r--src/librustc_metadata/rmeta/mod.rs4
-rw-r--r--src/librustc_middle/hir/map/mod.rs9
-rw-r--r--src/librustc_middle/hir/mod.rs20
-rw-r--r--src/librustc_middle/lint.rs4
-rw-r--r--src/librustc_middle/mir/mod.rs3
-rw-r--r--src/librustc_middle/mir/query.rs10
-rw-r--r--src/librustc_middle/query/mod.rs8
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs78
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs2
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mod.rs150
-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/diagnostics/region_errors.rs57
-rw-r--r--src/librustc_mir/borrow_check/mod.rs32
-rw-r--r--src/librustc_mir/borrow_check/nll.rs3
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs38
-rw-r--r--src/librustc_mir/borrow_check/region_infer/mod.rs18
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs27
-rw-r--r--src/librustc_mir/transform/check_consts/mod.rs1
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs16
-rw-r--r--src/librustc_mir/transform/check_consts/post_drop_elaboration.rs119
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs41
-rw-r--r--src/librustc_mir/transform/const_prop.rs1
-rw-r--r--src/librustc_mir/transform/mod.rs49
-rw-r--r--src/librustc_mir_build/hair/pattern/_match.rs542
-rw-r--r--src/librustc_mir_build/hair/pattern/const_to_pat.rs3
-rw-r--r--src/librustc_span/hygiene.rs13
-rw-r--r--src/librustc_span/lib.rs4
-rw-r--r--src/librustc_span/symbol.rs1
-rw-r--r--src/librustc_trait_selection/traits/structural_match.rs7
-rw-r--r--src/librustc_typeck/check/method/probe.rs3
-rw-r--r--src/test/ui/async-await/issue-69446-fnmut-capture.rs22
-rw-r--r--src/test/ui/async-await/issue-69446-fnmut-capture.stderr19
-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-describe-lvalue.stderr3
-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/consts/control-flow/drop-fail.precise.stderr15
-rw-r--r--src/test/ui/consts/control-flow/drop-fail.rs (renamed from src/test/ui/consts/control-flow/drop-failure.rs)13
-rw-r--r--src/test/ui/consts/control-flow/drop-fail.stock.stderr (renamed from src/test/ui/consts/control-flow/drop-failure.stderr)8
-rw-r--r--src/test/ui/consts/control-flow/drop-pass.rs (renamed from src/test/ui/consts/control-flow/drop-success.rs)2
-rw-r--r--src/test/ui/consts/control-flow/drop-precise.rs20
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.rs5
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.stderr4
-rw-r--r--src/test/ui/hygiene/unpretty-debug.stdout4
-rw-r--r--src/test/ui/impl-trait-in-bindings-issue-73003.rs8
-rw-r--r--src/test/ui/impl-trait-in-bindings-issue-73003.stderr11
-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-40510-1.stderr8
-rw-r--r--src/test/ui/issues/issue-40510-3.stderr4
-rw-r--r--src/test/ui/issues/issue-49824.stderr3
-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/nll/issue-53040.stderr8
-rw-r--r--src/test/ui/once-cant-call-twice-on-heap.stderr7
-rw-r--r--src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr8
-rw-r--r--src/test/ui/traits/trait-alias/issue-60021-assoc-method-resolve.rs19
-rw-r--r--src/test/ui/traits/trait-alias/issue-72415-assoc-const-resolve.rs14
-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
87 files changed, 1574 insertions, 507 deletions
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 2226737757b..06462fd96d9 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -2779,19 +2779,25 @@ impl<'a, T> Drain<'a, T> {
     /// # Examples
     ///
     /// ```
-    /// # #![feature(vec_drain_as_slice)]
     /// let mut vec = vec!['a', 'b', 'c'];
     /// let mut drain = vec.drain(..);
     /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
     /// let _ = drain.next().unwrap();
     /// assert_eq!(drain.as_slice(), &['b', 'c']);
     /// ```
-    #[unstable(feature = "vec_drain_as_slice", reason = "recently added", issue = "58957")]
+    #[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
     pub fn as_slice(&self) -> &[T] {
         self.iter.as_slice()
     }
 }
 
+#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
+impl<'a, T> AsRef<[T]> for Drain<'a, T> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
 #[stable(feature = "drain", since = "1.6.0")]
 unsafe impl<T: Sync> Sync for Drain<'_, T> {}
 #[stable(feature = "drain", since = "1.6.0")]
diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs
index 6f6009b47e6..9dbc23f5c04 100644
--- a/src/libcore/future/mod.rs
+++ b/src/libcore/future/mod.rs
@@ -56,6 +56,7 @@ pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
 where
     T: Generator<ResumeTy, Yield = ()>,
 {
+    #[rustc_diagnostic_item = "gen_future"]
     struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
 
     // We rely on the fact that async/await futures are immovable in order to create
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index a10b34d931d..fbfcdc3c1a9 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -2717,12 +2717,12 @@ pub trait Iterator {
     /// ```
     /// let a = [1, 2, 3];
     ///
-    /// let v_cloned: Vec<_> = a.iter().copied().collect();
+    /// let v_copied: Vec<_> = a.iter().copied().collect();
     ///
     /// // copied is the same as .map(|&x| x)
     /// let v_map: Vec<_> = a.iter().map(|&x| x).collect();
     ///
-    /// assert_eq!(v_cloned, vec![1, 2, 3]);
+    /// assert_eq!(v_copied, vec![1, 2, 3]);
     /// assert_eq!(v_map, vec![1, 2, 3]);
     /// ```
     #[stable(feature = "iter_copied", since = "1.36.0")]
diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs
index 263d6b5efdf..14f1f293d40 100644
--- a/src/libcore/str/pattern.rs
+++ b/src/libcore/str/pattern.rs
@@ -69,7 +69,7 @@ use crate::slice::memchr;
 /// |--------------------------|-------------------------------------------|
 /// | `&str`                   | is substring                              |
 /// | `char`                   | is contained in string                    |
-/// | `&[char]                 | any char in slice is contained in string  |
+/// | `&[char]`                | any char in slice is contained in string  |
 /// | `F: FnMut(char) -> bool` | `F` returns `true` for a char in string   |
 /// | `&&str`                  | is substring                              |
 /// | `&String`                | is substring                              |
@@ -117,6 +117,15 @@ pub trait Pattern<'a>: Sized {
         matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _))
     }
 
+    /// Checks whether the pattern matches at the back of the haystack
+    #[inline]
+    fn is_suffix_of(self, haystack: &'a str) -> bool
+    where
+        Self::Searcher: ReverseSearcher<'a>,
+    {
+        matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
+    }
+
     /// Removes the pattern from the front of haystack, if it matches.
     #[inline]
     fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
@@ -133,15 +142,6 @@ pub trait Pattern<'a>: Sized {
         }
     }
 
-    /// Checks whether the pattern matches at the back of the haystack
-    #[inline]
-    fn is_suffix_of(self, haystack: &'a str) -> bool
-    where
-        Self::Searcher: ReverseSearcher<'a>,
-    {
-        matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
-    }
-
     /// Removes the pattern from the back of haystack, if it matches.
     #[inline]
     fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index b7894eb145b..e59cacfffc9 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;
@@ -25,6 +25,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
+        let mut span = e.span;
         ensure_sufficient_stack(|| {
             let kind = match e.kind {
                 ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
@@ -53,6 +54,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
                 }
                 ExprKind::Binary(binop, ref lhs, ref rhs) => {
+                    span = self.mark_span_with_reason(DesugaringKind::Operator, e.span, None);
                     let binop = self.lower_binop(binop);
                     let lhs = self.lower_expr(lhs);
                     let rhs = self.lower_expr(rhs);
@@ -222,7 +224,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             hir::Expr {
                 hir_id: self.lower_node_id(e.id),
                 kind,
-                span: e.span,
+                span,
                 attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
             }
         })
@@ -237,6 +239,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
+        let span = self.mark_span_with_reason(DesugaringKind::Operator, b.span, None);
         Spanned {
             node: match b.node {
                 BinOpKind::Add => hir::BinOpKind::Add,
@@ -258,7 +261,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 BinOpKind::Ge => hir::BinOpKind::Ge,
                 BinOpKind::Gt => hir::BinOpKind::Gt,
             },
-            span: b.span,
+            span,
         }
     }
 
@@ -1360,9 +1363,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);
@@ -1457,10 +1465,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_error_codes/error_codes/E0446.md b/src/librustc_error_codes/error_codes/E0446.md
index 77a1834ece4..6ec47c4962c 100644
--- a/src/librustc_error_codes/error_codes/E0446.md
+++ b/src/librustc_error_codes/error_codes/E0446.md
@@ -4,10 +4,10 @@ Erroneous code example:
 
 ```compile_fail,E0446
 #![deny(private_in_public)]
+struct Bar(u32);
 
-mod Foo {
-    struct Bar(u32);
-
+mod foo {
+    use crate::Bar;
     pub fn bar() -> Bar { // error: private type in public interface
         Bar(0)
     }
@@ -16,15 +16,31 @@ mod Foo {
 fn main() {}
 ```
 
-To solve this error, please ensure that the type is also public. The type
-can be made inaccessible if necessary by placing it into a private inner
-module, but it still has to be marked with `pub`.
+There are two ways to solve this error. The first is to make the public type
+signature only public to a module that also has access to the private type.
+This is done by using pub(crate) or pub(in crate::my_mod::etc)
 Example:
 
 ```
-mod Foo {
-    pub struct Bar(u32); // we set the Bar type public
+struct Bar(u32);
+
+mod foo {
+    use crate::Bar;
+    pub(crate) fn bar() -> Bar { // only public to crate root
+        Bar(0)
+    }
+}
 
+fn main() {}
+```
+
+The other way to solve this error is to make the private type public.
+Example:
+
+```
+pub struct Bar(u32); // we set the Bar type public
+mod foo {
+    use crate::Bar;
     pub fn bar() -> Bar { // ok!
         Bar(0)
     }
diff --git a/src/librustc_error_codes/error_codes/E0493.md b/src/librustc_error_codes/error_codes/E0493.md
index 90a0cbce623..0dcc3b62b4b 100644
--- a/src/librustc_error_codes/error_codes/E0493.md
+++ b/src/librustc_error_codes/error_codes/E0493.md
@@ -1,5 +1,4 @@
-A type with a `Drop` implementation was destructured when trying to initialize
-a static item.
+A value with a custom `Drop` implementation may be dropped during const-eval.
 
 Erroneous code example:
 
@@ -16,13 +15,14 @@ struct Foo {
     field1: DropType,
 }
 
-static FOO: Foo = Foo { ..Foo { field1: DropType::A } }; // error!
+static FOO: Foo = Foo { field1: (DropType::A, DropType::A).1 }; // error!
 ```
 
 The problem here is that if the given type or one of its fields implements the
-`Drop` trait, this `Drop` implementation cannot be called during the static
-type initialization which might cause a memory leak. To prevent this issue,
-you need to instantiate all the static type's fields by hand.
+`Drop` trait, this `Drop` implementation cannot be called within a const
+context since it may run arbitrary, non-const-checked code. To prevent this
+issue, ensure all values with custom a custom `Drop` implementation escape the
+initializer.
 
 ```
 enum DropType {
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index b4935236b6a..d186f35a12b 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -577,6 +577,9 @@ declare_features! (
     /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`.
     (active, abi_avr_interrupt, "1.45.0", Some(69664), None),
 
+    /// Be more precise when looking for live drops in a const context.
+    (active, const_precise_live_drops, "1.46.0", Some(73255), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
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 ceaec2ba5db..1361d5bede6 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -455,7 +455,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_interface/passes.rs b/src/librustc_interface/passes.rs
index 1a9bf4e1e8f..1ed9bc3f1f5 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -847,7 +847,11 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
 
     sess.time("MIR_effect_checking", || {
         for def_id in tcx.body_owners() {
-            mir::transform::check_unsafety::check_unsafety(tcx, def_id)
+            mir::transform::check_unsafety::check_unsafety(tcx, def_id);
+
+            if tcx.hir().body_const_context(def_id).is_some() {
+                tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
+            }
         }
     });
 
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 44944a9fb26..edde82c40fb 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -1315,13 +1315,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         }
     }
 
-    fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Symbol] {
+    fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
         let param_names = match self.kind(id) {
             EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names,
             EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names,
             _ => Lazy::empty(),
         };
-        tcx.arena.alloc_from_iter(param_names.decode(self))
+        tcx.arena.alloc_from_iter(param_names.decode((self, tcx)))
     }
 
     fn exported_symbols(
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 1dc22c10c8e..721b4254c85 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder};
 use rustc_session::config::CrateType;
 use rustc_span::source_map::Spanned;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{self, ExternalSource, FileName, SourceFile, Span};
 use rustc_target::abi::VariantIdx;
 use std::hash::Hash;
@@ -994,18 +994,12 @@ impl EncodeContext<'tcx> {
         }
     }
 
-    fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Symbol]> {
-        self.tcx.dep_graph.with_ignore(|| {
-            let body = self.tcx.hir().body(body_id);
-            self.lazy(body.params.iter().map(|arg| match arg.pat.kind {
-                hir::PatKind::Binding(_, _, ident, _) => ident.name,
-                _ => kw::Invalid,
-            }))
-        })
+    fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
+        self.tcx.dep_graph.with_ignore(|| self.lazy(self.tcx.hir().body_param_names(body_id)))
     }
 
-    fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Symbol]> {
-        self.lazy(param_names.iter().map(|ident| ident.name))
+    fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Ident]> {
+        self.lazy(param_names.iter())
     }
 
     fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 626a436b400..ec80a2b6171 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -19,7 +19,7 @@ use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::CrateDisambiguator;
 use rustc_span::edition::Edition;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, Span};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
@@ -326,7 +326,7 @@ struct ModData {
 struct FnData {
     asyncness: hir::IsAsync,
     constness: hir::Constness,
-    param_names: Lazy<[Symbol]>,
+    param_names: Lazy<[Ident]>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs
index d1cfc4867a2..e3e0856ffc5 100644
--- a/src/librustc_middle/hir/map/mod.rs
+++ b/src/librustc_middle/hir/map/mod.rs
@@ -14,7 +14,7 @@ use rustc_hir::*;
 use rustc_index::vec::IndexVec;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
-use rustc_span::symbol::{kw, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
@@ -374,6 +374,13 @@ impl<'hir> Map<'hir> {
         })
     }
 
+    pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
+        self.body(id).params.iter().map(|arg| match arg.pat.kind {
+            PatKind::Binding(_, _, ident, _) => ident,
+            _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP),
+        })
+    }
+
     /// Returns the `BodyOwnerKind` of this `LocalDefId`.
     ///
     /// Panics if `LocalDefId` does not have an associated body.
diff --git a/src/librustc_middle/hir/mod.rs b/src/librustc_middle/hir/mod.rs
index 1e3676496ce..e152d11c081 100644
--- a/src/librustc_middle/hir/mod.rs
+++ b/src/librustc_middle/hir/mod.rs
@@ -12,10 +12,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
-use rustc_hir::Body;
-use rustc_hir::HirId;
-use rustc_hir::ItemLocalId;
-use rustc_hir::Node;
+use rustc_hir::*;
 use rustc_index::vec::IndexVec;
 
 pub struct Owner<'tcx> {
@@ -79,5 +76,20 @@ pub fn provide(providers: &mut Providers<'_>) {
     };
     providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
     providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
+    providers.fn_arg_names = |tcx, id| {
+        let hir = tcx.hir();
+        let hir_id = hir.as_local_hir_id(id.expect_local());
+        if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
+            tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
+        } else if let Node::TraitItem(&TraitItem {
+            kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
+            ..
+        }) = hir.get(hir_id)
+        {
+            tcx.arena.alloc_slice(idents)
+        } else {
+            span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
+        }
+    };
     map::provide(providers);
 }
diff --git a/src/librustc_middle/lint.rs b/src/librustc_middle/lint.rs
index 27239b4ad2e..923119e359c 100644
--- a/src/librustc_middle/lint.rs
+++ b/src/librustc_middle/lint.rs
@@ -339,7 +339,9 @@ 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(_))
+        | ExpnKind::Desugaring(DesugaringKind::Operator) => 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_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 129f9691ea5..21f5d9e7dd4 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -76,7 +76,8 @@ pub enum MirPhase {
     Build = 0,
     Const = 1,
     Validated = 2,
-    Optimized = 3,
+    DropElab = 3,
+    Optimized = 4,
 }
 
 impl MirPhase {
diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs
index 99bfb74c243..d82faf3e5fb 100644
--- a/src/librustc_middle/mir/query.rs
+++ b/src/librustc_middle/mir/query.rs
@@ -183,7 +183,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[derive(RustcEncodable, RustcDecodable, HashStable)]
 pub enum ConstraintCategory {
-    Return,
+    Return(ReturnConstraint),
     Yield,
     UseAsConst,
     UseAsStatic,
@@ -199,6 +199,7 @@ pub enum ConstraintCategory {
     SizedBound,
     Assignment,
     OpaqueType,
+    ClosureUpvar(hir::HirId),
 
     /// A "boring" constraint (caused by the given location) is one that
     /// the user probably doesn't want to see described in diagnostics,
@@ -216,6 +217,13 @@ pub enum ConstraintCategory {
     Internal,
 }
 
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
+pub enum ReturnConstraint {
+    Normal,
+    ClosureUpvar(hir::HirId),
+}
+
 /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
 /// that must outlive some region.
 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index be15e6c576f..3b6d54a1bc1 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -190,6 +190,12 @@ rustc_queries! {
             no_hash
         }
 
+        query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> Steal<mir::Body<'tcx>> {
+            storage(ArenaCacheSelector<'tcx>)
+            no_hash
+            desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.to_def_id()) }
+        }
+
         query mir_validated(key: LocalDefId) ->
             (
                 Steal<mir::Body<'tcx>>,
@@ -700,7 +706,7 @@ rustc_queries! {
     }
 
     Other {
-        query fn_arg_names(def_id: DefId) -> &'tcx [Symbol] {
+        query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
             desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
         }
         /// Gets the rendered value of the specified constant or associated constant.
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index d0050f801fc..2e897647a3b 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,13 +151,70 @@ 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 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(
@@ -766,7 +824,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     category:
                         category
                         @
-                        (ConstraintCategory::Return
+                        (ConstraintCategory::Return(_)
                         | ConstraintCategory::CallArgument
                         | ConstraintCategory::OpaqueType),
                     from_closure: false,
@@ -1089,7 +1147,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         opt_place_desc: Option<&String>,
     ) -> Option<DiagnosticBuilder<'cx>> {
         let return_kind = match category {
-            ConstraintCategory::Return => "return",
+            ConstraintCategory::Return(_) => "return",
             ConstraintCategory::Yield => "yield",
             _ => return None,
         };
@@ -1203,7 +1261,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         );
 
         let msg = match category {
-            ConstraintCategory::Return | ConstraintCategory::OpaqueType => {
+            ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
                 format!("{} is returned here", kind)
             }
             ConstraintCategory::CallArgument => {
diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 5253acbba7f..d04059ff0fc 100644
--- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -509,7 +509,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // Used in a closure.
                 (LaterUseKind::ClosureCapture, var_span)
             }
-            UseSpans::OtherUse(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 ca8e54ea286..04f48cd6582 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -11,7 +11,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 +37,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,33 +534,58 @@ 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 has a single span associated to it: common case.
     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::OtherUse(span) => span,
+            UseSpans::ClosureUse { args_span: span, .. }
+            | UseSpans::FnSelfUse { var_span: span, .. }
+            | UseSpans::OtherUse(span) => span,
         }
     }
 
     pub(super) fn var_or_use(self) -> Span {
         match self {
-            UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
+            UseSpans::ClosureUse { var_span: span, .. }
+            | UseSpans::FnSelfUse { var_span: span, .. }
+            | UseSpans::OtherUse(span) => span,
         }
     }
 
@@ -624,6 +654,7 @@ impl UseSpans {
     {
         match self {
             closure @ UseSpans::ClosureUse { .. } => closure,
+            fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
             UseSpans::OtherUse(_) => if_other(),
         }
     }
@@ -727,21 +758,100 @@ 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),
-            };
-
-            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 };
+                | 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 };
+                    }
+                }
+                _ => {}
             }
         }
 
-        OtherUse(stmt.source_info.span)
+        let normal_ret = OtherUse(stmt.source_info.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,
+        };
+
+        debug!("move_spans: target_temp = {:?}", target_temp);
+
+        if let Some(Terminator { kind: TerminatorKind::Call { func, args, fn_span, .. }, .. }) =
+            &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 is_fn_once = tcx.parent(method_did) == tcx.lang_items().fn_once_trait();
+                    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 fn_call_span.is_desugaring(DesugaringKind::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/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 727c4d0605e..f1923b9e81c 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -5,9 +5,9 @@ use rustc_infer::infer::{
     error_reporting::nice_region_error::NiceRegionError,
     error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
 };
-use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
 use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 
 use crate::util::borrowck_errors;
@@ -26,7 +26,7 @@ impl ConstraintDescription for ConstraintCategory {
         // Must end with a space. Allows for empty names to be provided.
         match self {
             ConstraintCategory::Assignment => "assignment ",
-            ConstraintCategory::Return => "returning this value ",
+            ConstraintCategory::Return(_) => "returning this value ",
             ConstraintCategory::Yield => "yielding this value ",
             ConstraintCategory::UseAsConst => "using this value as a constant ",
             ConstraintCategory::UseAsStatic => "using this value as a static ",
@@ -37,6 +37,7 @@ impl ConstraintDescription for ConstraintCategory {
             ConstraintCategory::SizedBound => "proving this value is `Sized` ",
             ConstraintCategory::CopyBound => "copying this value ",
             ConstraintCategory::OpaqueType => "opaque type ",
+            ConstraintCategory::ClosureUpvar(_) => "closure capture ",
             ConstraintCategory::Boring
             | ConstraintCategory::BoringNoLocation
             | ConstraintCategory::Internal => "",
@@ -306,8 +307,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         };
 
         let diag = match (category, fr_is_local, outlived_fr_is_local) {
-            (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(fr) => {
-                self.report_fnmut_error(&errci)
+            (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
+                self.report_fnmut_error(&errci, kind)
             }
             (ConstraintCategory::Assignment, true, false)
             | (ConstraintCategory::CallArgument, true, false) => {
@@ -347,7 +348,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     ///            executing...
     ///    = note: ...therefore, returned references to captured variables will escape the closure
     /// ```
-    fn report_fnmut_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> {
+    fn report_fnmut_error(
+        &self,
+        errci: &ErrorConstraintInfo,
+        kind: ReturnConstraint,
+    ) -> DiagnosticBuilder<'tcx> {
         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
 
         let mut diag = self
@@ -356,19 +361,39 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             .sess
             .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
 
-        // We should check if the return type of this closure is in fact a closure - in that
-        // case, we can special case the error further.
-        let return_type_is_closure =
-            self.regioncx.universal_regions().unnormalized_output_ty.is_closure();
-        let message = if return_type_is_closure {
-            "returns a closure that contains a reference to a captured variable, which then \
-             escapes the closure body"
-        } else {
-            "returns a reference to a captured variable which escapes the closure body"
+        let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
+        if let ty::Opaque(def_id, _) = output_ty.kind {
+            output_ty = self.infcx.tcx.type_of(def_id)
+        };
+
+        debug!("report_fnmut_error: output_ty={:?}", output_ty);
+
+        let message = match output_ty.kind {
+            ty::Closure(_, _) => {
+                "returns a closure that contains a reference to a captured variable, which then \
+                 escapes the closure body"
+            }
+            ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did) => {
+                "returns an `async` block that contains a reference to a captured variable, which then \
+                 escapes the closure body"
+            }
+            _ => "returns a reference to a captured variable which escapes the closure body",
         };
 
         diag.span_label(*span, message);
 
+        if let ReturnConstraint::ClosureUpvar(upvar) = kind {
+            let def_id = match self.regioncx.universal_regions().defining_ty {
+                DefiningTy::Closure(def_id, _) => def_id,
+                ty @ _ => bug!("unexpected DefiningTy {:?}", ty),
+            };
+
+            let upvar_def_span = self.infcx.tcx.hir().span(upvar);
+            let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span;
+            diag.span_label(upvar_def_span, "variable defined here");
+            diag.span_label(upvar_span, "variable captured here");
+        }
+
         match self.give_region_a_name(*outlived_fr).unwrap().source {
             RegionNameSource::NamedEarlyBoundRegion(fr_span)
             | RegionNameSource::NamedFreeRegion(fr_span)
@@ -506,7 +531,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         outlived_fr_name.highlight_region_name(&mut diag);
 
         match (category, outlived_fr_is_local, fr_is_local) {
-            (ConstraintCategory::Return, true, _) => {
+            (ConstraintCategory::Return(_), true, _) => {
                 diag.span_label(
                     *span,
                     format!(
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index b703237a18e..d099f48adc5 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -216,6 +216,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         &mut flow_inits,
         &mdpe.move_data,
         &borrow_set,
+        &upvars,
     );
 
     // Dump MIR results into a file, if that is enabled. This let us
@@ -277,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(),
@@ -310,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(),
@@ -486,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.
@@ -2308,30 +2315,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// be `self` in the current MIR, because that is the only time we directly access the fields
     /// of a closure type.
     pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
-        let mut place_projection = place_ref.projection;
-        let mut by_ref = false;
-
-        if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
-            place_projection = proj_base;
-            by_ref = true;
-        }
-
-        match place_projection {
-            [base @ .., ProjectionElem::Field(field, _ty)] => {
-                let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty;
-
-                if (base_ty.is_closure() || base_ty.is_generator())
-                    && (!by_ref || self.upvars[field.index()].by_ref)
-                {
-                    Some(*field)
-                } else {
-                    None
-                }
-            }
-
-            _ => None,
-        }
+        path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index 375b3210e8c..ea68364be37 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -39,6 +39,7 @@ use crate::borrow_check::{
     renumber,
     type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
     universal_regions::UniversalRegions,
+    Upvar,
 };
 
 crate type PoloniusOutput = Output<RustcFacts>;
@@ -166,6 +167,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
+    upvars: &[Upvar],
 ) -> NllOutput<'tcx> {
     let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
 
@@ -188,6 +190,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
             flow_inits,
             move_data,
             elements,
+            upvars,
         );
 
     if let Some(all_facts) = &mut all_facts {
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index f5238e7b7be..934729553a7 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -1,10 +1,11 @@
 use crate::borrow_check::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
 use crate::borrow_check::places_conflict;
 use crate::borrow_check::AccessDepth;
+use crate::borrow_check::Upvar;
 use crate::dataflow::indexes::BorrowIndex;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::BorrowKind;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place};
+use rustc_middle::mir::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::TyCtxt;
 
 /// Returns `true` if the borrow represented by `kind` is
@@ -135,3 +136,38 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
     // Any errors will be caught on the initial borrow
     !place.is_indirect()
 }
+
+/// If `place` is a field projection, and the field is being projected from a closure type,
+/// then returns the index of the field being projected. Note that this closure will always
+/// be `self` in the current MIR, because that is the only time we directly access the fields
+/// of a closure type.
+pub(crate) fn is_upvar_field_projection(
+    tcx: TyCtxt<'tcx>,
+    upvars: &[Upvar],
+    place_ref: PlaceRef<'tcx>,
+    body: &Body<'tcx>,
+) -> Option<Field> {
+    let mut place_projection = place_ref.projection;
+    let mut by_ref = false;
+
+    if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
+        place_projection = proj_base;
+        by_ref = true;
+    }
+
+    match place_projection {
+        [base @ .., ProjectionElem::Field(field, _ty)] => {
+            let base_ty = Place::ty_from(place_ref.local, base, body, tcx).ty;
+
+            if (base_ty.is_closure() || base_ty.is_generator())
+                && (!by_ref || upvars[field.index()].by_ref)
+            {
+                Some(*field)
+            } else {
+                None
+            }
+        }
+
+        _ => None,
+    }
+}
diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs
index fe113843800..3e459bd52f7 100644
--- a/src/librustc_mir/borrow_check/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/region_infer/mod.rs
@@ -12,7 +12,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}
 use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
 use rustc_middle::mir::{
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-    ConstraintCategory, Local, Location,
+    ConstraintCategory, Local, Location, ReturnConstraint,
 };
 use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
@@ -2017,7 +2017,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     | ConstraintCategory::BoringNoLocation
                     | ConstraintCategory::Internal => false,
                     ConstraintCategory::TypeAnnotation
-                    | ConstraintCategory::Return
+                    | ConstraintCategory::Return(_)
                     | ConstraintCategory::Yield => true,
                     _ => constraint_sup_scc != target_scc,
                 }
@@ -2042,7 +2042,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         if let Some(i) = best_choice {
             if let Some(next) = categorized_path.get(i + 1) {
-                if categorized_path[i].0 == ConstraintCategory::Return
+                if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
                     && next.0 == ConstraintCategory::OpaqueType
                 {
                     // The return expression is being influenced by the return type being
@@ -2050,6 +2050,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     return *next;
                 }
             }
+
+            if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
+                let field = categorized_path.iter().find_map(|p| {
+                    if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
+                });
+
+                if let Some(field) = field {
+                    categorized_path[i].0 =
+                        ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
+                }
+            }
+
             return categorized_path[i];
         }
 
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index e2255d170f9..168612f9bee 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -55,6 +55,7 @@ use crate::borrow_check::{
     location::LocationTable,
     member_constraints::MemberConstraintSet,
     nll::ToRegionVid,
+    path_utils,
     region_infer::values::{
         LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
     },
@@ -62,6 +63,7 @@ use crate::borrow_check::{
     renumber,
     type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
     universal_regions::{DefiningTy, UniversalRegions},
+    Upvar,
 };
 
 macro_rules! span_mirbug {
@@ -132,6 +134,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
     elements: &Rc<RegionValueElements>,
+    upvars: &[Upvar],
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
     let mut constraints = MirTypeckRegionConstraints {
@@ -162,6 +165,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         borrow_set,
         all_facts,
         constraints: &mut constraints,
+        upvars,
     };
 
     let opaque_type_values = type_check_internal(
@@ -577,7 +581,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         for constraint in constraints.outlives().iter() {
             let mut constraint = *constraint;
             constraint.locations = locations;
-            if let ConstraintCategory::Return
+            if let ConstraintCategory::Return(_)
             | ConstraintCategory::UseAsConst
             | ConstraintCategory::UseAsStatic = constraint.category
             {
@@ -827,6 +831,7 @@ struct BorrowCheckContext<'a, 'tcx> {
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
+    upvars: &'a [Upvar],
 }
 
 crate struct MirTypeckResults<'tcx> {
@@ -1420,7 +1425,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 ConstraintCategory::UseAsConst
                             }
                         } else {
-                            ConstraintCategory::Return
+                            ConstraintCategory::Return(ReturnConstraint::Normal)
                         }
                     }
                     Some(l) if !body.local_decls[l].is_user_variable() => {
@@ -1703,7 +1708,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 ConstraintCategory::UseAsConst
                             }
                         } else {
-                            ConstraintCategory::Return
+                            ConstraintCategory::Return(ReturnConstraint::Normal)
                         }
                     }
                     Some(l) if !body.local_decls[l].is_user_variable() => {
@@ -2489,6 +2494,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         let mut cursor = borrowed_place.projection.as_ref();
+        let tcx = self.infcx.tcx;
+        let field = path_utils::is_upvar_field_projection(
+            tcx,
+            &self.borrowck_context.upvars,
+            borrowed_place.as_ref(),
+            body,
+        );
+        let category = if let Some(field) = field {
+            ConstraintCategory::ClosureUpvar(self.borrowck_context.upvars[field.index()].var_hir_id)
+        } else {
+            ConstraintCategory::Boring
+        };
+
         while let [proj_base @ .., elem] = cursor {
             cursor = proj_base;
 
@@ -2496,7 +2514,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
             match elem {
                 ProjectionElem::Deref => {
-                    let tcx = self.infcx.tcx;
                     let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
@@ -2506,7 +2523,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 sup: ref_region.to_region_vid(),
                                 sub: borrow_region.to_region_vid(),
                                 locations: location.to_locations(),
-                                category: ConstraintCategory::Boring,
+                                category,
                             });
 
                             match mutbl {
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index 7c439f80ef6..e4aa88e3c20 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
 pub use self::qualifs::Qualif;
 
 mod ops;
+pub mod post_drop_elaboration;
 pub mod qualifs;
 mod resolver;
 pub mod validation;
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 92bd740e27a..d5059c98c95 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -10,6 +10,22 @@ use rustc_span::{Span, Symbol};
 
 use super::ConstCx;
 
+/// Emits an error if `op` is not allowed in the given const context.
+pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
+    debug!("illegal_op: op={:?}", op);
+
+    if op.is_allowed_in_item(ccx) {
+        return;
+    }
+
+    if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+        ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
+        return;
+    }
+
+    op.emit_error(ccx, span);
+}
+
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
     /// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
new file mode 100644
index 00000000000..226e0e2049e
--- /dev/null
+++ b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
@@ -0,0 +1,119 @@
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::{self, BasicBlock, Location};
+use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
+
+use super::ops;
+use super::qualifs::{NeedsDrop, Qualif};
+use super::validation::Qualifs;
+use super::ConstCx;
+
+/// Returns `true` if we should use the more precise live drop checker that runs after drop
+/// elaboration.
+pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool {
+    tcx.features().const_precise_live_drops
+}
+
+/// Look for live drops in a const context.
+///
+/// This is separate from the rest of the const checking logic because it must run after drop
+/// elaboration.
+pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<'tcx>) {
+    let const_kind = tcx.hir().body_const_context(def_id);
+    if const_kind.is_none() {
+        return;
+    }
+
+    if !checking_enabled(tcx) {
+        return;
+    }
+
+    let ccx = ConstCx {
+        body,
+        tcx,
+        def_id: def_id.to_def_id(),
+        const_kind,
+        param_env: tcx.param_env(def_id),
+    };
+
+    let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
+
+    visitor.visit_body(body);
+}
+
+struct CheckLiveDrops<'mir, 'tcx> {
+    ccx: &'mir ConstCx<'mir, 'tcx>,
+    qualifs: Qualifs<'mir, 'tcx>,
+}
+
+// So we can access `body` and `tcx`.
+impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
+    type Target = ConstCx<'mir, 'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.ccx
+    }
+}
+
+impl CheckLiveDrops<'mir, 'tcx> {
+    fn check_live_drop(&self, span: Span) {
+        ops::non_const(self.ccx, ops::LiveDrop, span);
+    }
+}
+
+impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
+    fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) {
+        trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
+
+        // Ignore drop terminators in cleanup blocks.
+        if block.is_cleanup {
+            return;
+        }
+
+        self.super_basic_block_data(bb, block);
+    }
+
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+        trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
+
+        match &terminator.kind {
+            mir::TerminatorKind::Drop { location: dropped_place, .. } => {
+                let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
+                if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
+                    return;
+                }
+
+                if dropped_place.is_indirect() {
+                    self.check_live_drop(terminator.source_info.span);
+                    return;
+                }
+
+                if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
+                    // Use the span where the dropped local was declared for the error.
+                    let span = self.body.local_decls[dropped_place.local].source_info.span;
+                    self.check_live_drop(span);
+                }
+            }
+
+            mir::TerminatorKind::DropAndReplace { .. } => span_bug!(
+                terminator.source_info.span,
+                "`DropAndReplace` should be removed by drop elaboration",
+            ),
+
+            mir::TerminatorKind::Abort
+            | mir::TerminatorKind::Call { .. }
+            | mir::TerminatorKind::Assert { .. }
+            | mir::TerminatorKind::FalseEdge { .. }
+            | mir::TerminatorKind::FalseUnwind { .. }
+            | mir::TerminatorKind::GeneratorDrop
+            | mir::TerminatorKind::Goto { .. }
+            | mir::TerminatorKind::InlineAsm { .. }
+            | mir::TerminatorKind::Resume
+            | mir::TerminatorKind::Return
+            | mir::TerminatorKind::SwitchInt { .. }
+            | mir::TerminatorKind::Unreachable
+            | mir::TerminatorKind::Yield { .. } => {}
+        }
+    }
+}
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index ab87d70da7d..428a74bcdcb 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -40,7 +40,7 @@ pub struct Qualifs<'mir, 'tcx> {
 }
 
 impl Qualifs<'mir, 'tcx> {
-    fn indirectly_mutable(
+    pub fn indirectly_mutable(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
         local: Local,
@@ -68,7 +68,7 @@ impl Qualifs<'mir, 'tcx> {
     /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary
-    fn needs_drop(
+    pub fn needs_drop(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
         local: Local,
@@ -95,7 +95,7 @@ impl Qualifs<'mir, 'tcx> {
     /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary.
-    fn has_mut_interior(
+    pub fn has_mut_interior(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
         local: Local,
@@ -232,30 +232,15 @@ impl Validator<'mir, 'tcx> {
         self.qualifs.in_return_place(self.ccx)
     }
 
-    /// Emits an error at the given `span` if an expression cannot be evaluated in the current
-    /// context.
-    pub fn check_op_spanned<O>(&mut self, op: O, span: Span)
-    where
-        O: NonConstOp,
-    {
-        debug!("check_op: op={:?}", op);
-
-        if op.is_allowed_in_item(self) {
-            return;
-        }
-
-        if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
-            self.tcx.sess.miri_unleashed_feature(span, O::feature_gate());
-            return;
-        }
-
-        op.emit_error(self, span);
-    }
-
     /// Emits an error if an expression cannot be evaluated in the current context.
     pub fn check_op(&mut self, op: impl NonConstOp) {
-        let span = self.span;
-        self.check_op_spanned(op, span)
+        ops::non_const(self.ccx, op, self.span);
+    }
+
+    /// Emits an error at the given `span` if an expression cannot be evaluated in the current
+    /// context.
+    pub fn check_op_spanned(&mut self, op: impl NonConstOp, span: Span) {
+        ops::non_const(self.ccx, op, span);
     }
 
     fn check_static(&mut self, def_id: DefId, span: Span) {
@@ -577,6 +562,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
             // projections that cannot be `NeedsDrop`.
             TerminatorKind::Drop { location: dropped_place, .. }
             | TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
+                // If we are checking live drops after drop-elaboration, don't emit duplicate
+                // errors here.
+                if super::post_drop_elaboration::checking_enabled(self.tcx) {
+                    return;
+                }
+
                 let mut err_span = self.span;
 
                 // Check to see if the type of this place can ever have a drop impl. If not, this
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 0ff60cbd55d..72db35de408 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -511,6 +511,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_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 26725a2ac02..4240b528a61 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -49,6 +49,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
         mir_const,
         mir_const_qualif,
         mir_validated,
+        mir_drops_elaborated_and_const_checked,
         optimized_mir,
         is_mir_available,
         promoted_mir,
@@ -294,12 +295,31 @@ fn mir_validated(
     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
 }
 
-fn run_optimization_passes<'tcx>(
+fn mir_drops_elaborated_and_const_checked<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> Steal<Body<'tcx>> {
+    // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
+    // execute before we can steal.
+    tcx.ensure().mir_borrowck(def_id);
+
+    let (body, _) = tcx.mir_validated(def_id);
+    let mut body = body.steal();
+
+    run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, None);
+    check_consts::post_drop_elaboration::check_live_drops(tcx, def_id, &body);
+    tcx.alloc_steal_mir(body)
+}
+
+/// After this series of passes, no lifetime analysis based on borrowing can be done.
+fn run_post_borrowck_cleanup_passes<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     def_id: LocalDefId,
     promoted: Option<Promoted>,
 ) {
+    debug!("post_borrowck_cleanup({:?})", def_id);
+
     let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
         // Remove all things only needed by analysis
         &no_landing_pads::NoLandingPads::new(tcx),
@@ -318,9 +338,24 @@ fn run_optimization_passes<'tcx>(
         // but before optimizations begin.
         &add_retag::AddRetag,
         &simplify::SimplifyCfg::new("elaborate-drops"),
-        // No lifetime analysis based on borrowing can be done from here on out.
     ];
 
+    run_passes(
+        tcx,
+        body,
+        InstanceDef::Item(def_id.to_def_id()),
+        promoted,
+        MirPhase::DropElab,
+        &[post_borrowck_cleanup],
+    );
+}
+
+fn run_optimization_passes<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &mut Body<'tcx>,
+    def_id: LocalDefId,
+    promoted: Option<Promoted>,
+) {
     let optimizations: &[&dyn MirPass<'tcx>] = &[
         &unreachable_prop::UnreachablePropagation,
         &uninhabited_enum_branching::UninhabitedEnumBranching,
@@ -368,6 +403,7 @@ fn run_optimization_passes<'tcx>(
 
     let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level;
 
+    #[rustfmt::skip]
     run_passes(
         tcx,
         body,
@@ -375,7 +411,6 @@ fn run_optimization_passes<'tcx>(
         promoted,
         MirPhase::Optimized,
         &[
-            post_borrowck_cleanup,
             if mir_opt_level > 0 { optimizations } else { no_optimizations },
             pre_codegen_cleanup,
         ],
@@ -393,12 +428,7 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
 
     let def_id = def_id.expect_local();
 
-    // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
-    // execute before we can steal.
-    tcx.ensure().mir_borrowck(def_id);
-
-    let (body, _) = tcx.mir_validated(def_id);
-    let mut body = body.steal();
+    let mut body = tcx.mir_drops_elaborated_and_const_checked(def_id).steal();
     run_optimization_passes(tcx, &mut body, def_id, None);
 
     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
@@ -418,6 +448,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> IndexVec<Promoted, Body<'_>>
     let mut promoted = promoted.steal();
 
     for (p, mut body) in promoted.iter_enumerated_mut() {
+        run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, Some(p));
         run_optimization_passes(tcx, &mut body, def_id, Some(p));
     }
 
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index dc7d8098e55..4a4de6c420b 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -1,274 +1,274 @@
-/// Note: most of the tests relevant to this file can be found (at the time of writing) in
-/// src/tests/ui/pattern/usefulness.
-///
-/// This file includes the logic for exhaustiveness and usefulness checking for
-/// pattern-matching. Specifically, given a list of patterns for a type, we can
-/// tell whether:
-/// (a) the patterns cover every possible constructor for the type [exhaustiveness]
-/// (b) each pattern is necessary [usefulness]
-///
-/// The algorithm implemented here is a modified version of the one described in:
-/// http://moscova.inria.fr/~maranget/papers/warn/index.html
-/// However, to save future implementors from reading the original paper, we
-/// summarise the algorithm here to hopefully save time and be a little clearer
-/// (without being so rigorous).
-///
-/// # Premise
-///
-/// The core of the algorithm revolves about a "usefulness" check. In particular, we
-/// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
-/// a matrix). `U(P, p)` represents whether, given an existing list of patterns
-/// `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
-/// uncovered values of the type).
-///
-/// If we have this predicate, then we can easily compute both exhaustiveness of an
-/// entire set of patterns and the individual usefulness of each one.
-/// (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
-/// match doesn't increase the number of values we're matching)
-/// (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
-/// pattern to those that have come before it doesn't increase the number of values
-/// we're matching).
-///
-/// # Core concept
-///
-/// The idea that powers everything that is done in this file is the following: a value is made
-/// from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)`
-/// (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the
-/// constructor for the number `2`). Fields are just a (possibly empty) list of values.
-///
-/// Some of the constructors listed above might feel weird: `None` and `2` don't take any
-/// arguments. This is part of what makes constructors so general: we will consider plain values
-/// like numbers and string literals to be constructors that take no arguments, also called "0-ary
-/// constructors"; they are the simplest case of constructors. This allows us to see any value as
-/// made up from a tree of constructors, each having a given number of children. For example:
-/// `(None, Ok(0))` is made from 4 different constructors.
-///
-/// This idea can be extended to patterns: a pattern captures a set of possible values, and we can
-/// describe this set using constructors. For example, `Err(_)` captures all values of the type
-/// `Result<T, E>` that start with the `Err` constructor (for some choice of `T` and `E`). The
-/// wildcard `_` captures all values of the given type starting with any of the constructors for
-/// that type.
-///
-/// We use this to compute whether different patterns might capture a same value. Do the patterns
-/// `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern
-/// captures only values starting with the `Ok` constructor and the second only values starting
-/// with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might,
-/// since they both capture values starting with `Some`. To be certain, we need to dig under the
-/// `Some` constructor and continue asking the question. This is the main idea behind the
-/// exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently
-/// figure out if some new pattern might capture a value that hadn't been captured by previous
-/// patterns.
-///
-/// Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum.
-/// Most of the complexity of this file resides in transforming between patterns and
-/// (`Constructor`, `Fields`) pairs, handling all the special cases correctly.
-///
-/// Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example
-/// a value of type `Rc<u64>` doesn't fit this idea very well, nor do various other things.
-/// However, this idea covers most of the cases that are relevant to exhaustiveness checking.
-///
-///
-/// # Algorithm
-///
-/// Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`,
-/// adding a new pattern `p` will cover previously-uncovered values of the type.
-/// During the course of the algorithm, the rows of the matrix won't just be individual patterns,
-/// but rather partially-deconstructed patterns in the form of a list of fields. The paper
-/// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
-/// new pattern `p`.
-///
-/// For example, say we have the following:
-/// ```
-///     // x: (Option<bool>, Result<()>)
-///     match x {
-///         (Some(true), _) => {}
-///         (None, Err(())) => {}
-///         (None, Err(_)) => {}
-///     }
-/// ```
-/// Here, the matrix `P` starts as:
-/// [
-///     [(Some(true), _)],
-///     [(None, Err(()))],
-///     [(None, Err(_))],
-/// ]
-/// We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
-/// `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
-/// all the values it covers are already covered by row 2.
-///
-/// A list of patterns can be thought of as a stack, because we are mainly interested in the top of
-/// the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
-/// To match the paper, the top of the stack is at the beginning / on the left.
-///
-/// There are two important operations on pattern-stacks necessary to understand the algorithm:
-///     1. We can pop a given constructor off the top of a stack. This operation is called
-///        `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
-///        `None`) and `p` a pattern-stack.
-///        If the pattern on top of the stack can cover `c`, this removes the constructor and
-///        pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
-///        Otherwise the pattern-stack is discarded.
-///        This essentially filters those pattern-stacks whose top covers the constructor `c` and
-///        discards the others.
-///
-///        For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
-///        pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
-///        `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
-///        nothing back.
-///
-///        This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
-///        on top of the stack, and we have four cases:
-///             1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
-///                  push onto the stack the arguments of this constructor, and return the result:
-///                     r_1, .., r_a, p_2, .., p_n
-///             1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
-///                  return nothing.
-///             1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
-///                  arguments (its arity), and return the resulting stack:
-///                     _, .., _, p_2, .., p_n
-///             1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-///                  stack:
-///                     S(c, (r_1, p_2, .., p_n))
-///                     S(c, (r_2, p_2, .., p_n))
-///
-///     2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
-///        a pattern-stack.
-///        This is used when we know there are missing constructor cases, but there might be
-///        existing wildcard patterns, so to check the usefulness of the matrix, we have to check
-///        all its *other* components.
-///
-///        It is computed as follows. We look at the pattern `p_1` on top of the stack,
-///        and we have three cases:
-///             1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
-///             1.2. `p_1 = _`. We return the rest of the stack:
-///                     p_2, .., p_n
-///             1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-///               stack.
-///                     D((r_1, p_2, .., p_n))
-///                     D((r_2, p_2, .., p_n))
-///
-///     Note that the OR-patterns are not always used directly in Rust, but are used to derive the
-///     exhaustive integer matching rules, so they're written here for posterity.
-///
-/// Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
-/// working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
-/// the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
-///
-///
-/// The algorithm for computing `U`
-/// -------------------------------
-/// The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
-/// That means we're going to check the components from left-to-right, so the algorithm
-/// operates principally on the first component of the matrix and new pattern-stack `p`.
-/// This algorithm is realised in the `is_useful` function.
-///
-/// Base case. (`n = 0`, i.e., an empty tuple pattern)
-///     - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
-///       then `U(P, p)` is false.
-///     - Otherwise, `P` must be empty, so `U(P, p)` is true.
-///
-/// Inductive step. (`n > 0`, i.e., whether there's at least one column
-///                  [which may then be expanded into further columns later])
-///     We're going to match on the top of the new pattern-stack, `p_1`.
-///         - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
-///           Then, the usefulness of `p_1` can be reduced to whether it is useful when
-///           we ignore all the patterns in the first column of `P` that involve other constructors.
-///           This is where `S(c, P)` comes in:
-///           `U(P, p) := U(S(c, P), S(c, p))`
-///           This special case is handled in `is_useful_specialized`.
-///
-///           For example, if `P` is:
-///           [
-///               [Some(true), _],
-///               [None, 0],
-///           ]
-///           and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
-///           matches values that row 2 doesn't. For row 1 however, we need to dig into the
-///           arguments of `Some` to know whether some new value is covered. So we compute
-///           `U([[true, _]], [false, 0])`.
-///
-///         - If `p_1 == _`, then we look at the list of constructors that appear in the first
-///               component of the rows of `P`:
-///             + If there are some constructors that aren't present, then we might think that the
-///               wildcard `_` is useful, since it covers those constructors that weren't covered
-///               before.
-///               That's almost correct, but only works if there were no wildcards in those first
-///               components. So we need to check that `p` is useful with respect to the rows that
-///               start with a wildcard, if there are any. This is where `D` comes in:
-///               `U(P, p) := U(D(P), D(p))`
-///
-///               For example, if `P` is:
-///               [
-///                   [_, true, _],
-///                   [None, false, 1],
-///               ]
-///               and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
-///               only had row 2, we'd know that `p` is useful. However row 1 starts with a
-///               wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
-///
-///             + Otherwise, all possible constructors (for the relevant type) are present. In this
-///               case we must check whether the wildcard pattern covers any unmatched value. For
-///               that, we can think of the `_` pattern as a big OR-pattern that covers all
-///               possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
-///               example. The wildcard pattern is useful in this case if it is useful when
-///               specialized to one of the possible constructors. So we compute:
-///               `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
-///
-///               For example, if `P` is:
-///               [
-///                   [Some(true), _],
-///                   [None, false],
-///               ]
-///               and `p` is [_, false], both `None` and `Some` constructors appear in the first
-///               components of `P`. We will therefore try popping both constructors in turn: we
-///               compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]],
-///               [false]) for the `None` constructor. The first case returns true, so we know that
-///               `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
-///               before.
-///
-///         - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
-///           `U(P, p) := U(P, (r_1, p_2, .., p_n))
-///                    || U(P, (r_2, p_2, .., p_n))`
-///
-/// Modifications to the algorithm
-/// ------------------------------
-/// The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for
-/// example uninhabited types and variable-length slice patterns. These are drawn attention to
-/// throughout the code below. I'll make a quick note here about how exhaustive integer matching is
-/// accounted for, though.
-///
-/// Exhaustive integer matching
-/// ---------------------------
-/// An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ...
-/// So to support exhaustive integer matching, we can make use of the logic in the paper for
-/// OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because
-/// they are likely gigantic. So we instead treat ranges as constructors of the integers. This means
-/// that we have a constructor *of* constructors (the integers themselves). We then need to work
-/// through all the inductive step rules above, deriving how the ranges would be treated as
-/// OR-patterns, and making sure that they're treated in the same way even when they're ranges.
-/// There are really only four special cases here:
-/// - When we match on a constructor that's actually a range, we have to treat it as if we would
-///   an OR-pattern.
-///     + It turns out that we can simply extend the case for single-value patterns in
-///      `specialize` to either be *equal* to a value constructor, or *contained within* a range
-///      constructor.
-///     + When the pattern itself is a range, you just want to tell whether any of the values in
-///       the pattern range coincide with values in the constructor range, which is precisely
-///       intersection.
-///   Since when encountering a range pattern for a value constructor, we also use inclusion, it
-///   means that whenever the constructor is a value/range and the pattern is also a value/range,
-///   we can simply use intersection to test usefulness.
-/// - When we're testing for usefulness of a pattern and the pattern's first component is a
-///   wildcard.
-///     + If all the constructors appear in the matrix, we have a slight complication. By default,
-///       the behaviour (i.e., a disjunction over specialised matrices for each constructor) is
-///       invalid, because we want a disjunction over every *integer* in each range, not just a
-///       disjunction over every range. This is a bit more tricky to deal with: essentially we need
-///       to form equivalence classes of subranges of the constructor range for which the behaviour
-///       of the matrix `P` and new pattern `p` are the same. This is described in more
-///       detail in `split_grouped_constructors`.
-///     + If some constructors are missing from the matrix, it turns out we don't need to do
-///       anything special (because we know none of the integers are actually wildcards: i.e., we
-///       can't span wildcards using ranges).
+//! Note: most of the tests relevant to this file can be found (at the time of writing) in
+//! src/tests/ui/pattern/usefulness.
+//!
+//! This file includes the logic for exhaustiveness and usefulness checking for
+//! pattern-matching. Specifically, given a list of patterns for a type, we can
+//! tell whether:
+//! (a) the patterns cover every possible constructor for the type [exhaustiveness]
+//! (b) each pattern is necessary [usefulness]
+//!
+//! The algorithm implemented here is a modified version of the one described in:
+//! http://moscova.inria.fr/~maranget/papers/warn/index.html
+//! However, to save future implementors from reading the original paper, we
+//! summarise the algorithm here to hopefully save time and be a little clearer
+//! (without being so rigorous).
+//!
+//! # Premise
+//!
+//! The core of the algorithm revolves about a "usefulness" check. In particular, we
+//! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
+//! a matrix). `U(P, p)` represents whether, given an existing list of patterns
+//! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
+//! uncovered values of the type).
+//!
+//! If we have this predicate, then we can easily compute both exhaustiveness of an
+//! entire set of patterns and the individual usefulness of each one.
+//! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
+//! match doesn't increase the number of values we're matching)
+//! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
+//! pattern to those that have come before it doesn't increase the number of values
+//! we're matching).
+//!
+//! # Core concept
+//!
+//! The idea that powers everything that is done in this file is the following: a value is made
+//! from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)`
+//! (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the
+//! constructor for the number `2`). Fields are just a (possibly empty) list of values.
+//!
+//! Some of the constructors listed above might feel weird: `None` and `2` don't take any
+//! arguments. This is part of what makes constructors so general: we will consider plain values
+//! like numbers and string literals to be constructors that take no arguments, also called "0-ary
+//! constructors"; they are the simplest case of constructors. This allows us to see any value as
+//! made up from a tree of constructors, each having a given number of children. For example:
+//! `(None, Ok(0))` is made from 4 different constructors.
+//!
+//! This idea can be extended to patterns: a pattern captures a set of possible values, and we can
+//! describe this set using constructors. For example, `Err(_)` captures all values of the type
+//! `Result<T, E>` that start with the `Err` constructor (for some choice of `T` and `E`). The
+//! wildcard `_` captures all values of the given type starting with any of the constructors for
+//! that type.
+//!
+//! We use this to compute whether different patterns might capture a same value. Do the patterns
+//! `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern
+//! captures only values starting with the `Ok` constructor and the second only values starting
+//! with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might,
+//! since they both capture values starting with `Some`. To be certain, we need to dig under the
+//! `Some` constructor and continue asking the question. This is the main idea behind the
+//! exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently
+//! figure out if some new pattern might capture a value that hadn't been captured by previous
+//! patterns.
+//!
+//! Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum.
+//! Most of the complexity of this file resides in transforming between patterns and
+//! (`Constructor`, `Fields`) pairs, handling all the special cases correctly.
+//!
+//! Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example
+//! a value of type `Rc<u64>` doesn't fit this idea very well, nor do various other things.
+//! However, this idea covers most of the cases that are relevant to exhaustiveness checking.
+//!
+//!
+//! # Algorithm
+//!
+//! Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`,
+//! adding a new pattern `p` will cover previously-uncovered values of the type.
+//! During the course of the algorithm, the rows of the matrix won't just be individual patterns,
+//! but rather partially-deconstructed patterns in the form of a list of fields. The paper
+//! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
+//! new pattern `p`.
+//!
+//! For example, say we have the following:
+//! ```
+//!     // x: (Option<bool>, Result<()>)
+//!     match x {
+//!         (Some(true), _) => {}
+//!         (None, Err(())) => {}
+//!         (None, Err(_)) => {}
+//!     }
+//! ```
+//! Here, the matrix `P` starts as:
+//! [
+//!     [(Some(true), _)],
+//!     [(None, Err(()))],
+//!     [(None, Err(_))],
+//! ]
+//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
+//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
+//! all the values it covers are already covered by row 2.
+//!
+//! A list of patterns can be thought of as a stack, because we are mainly interested in the top of
+//! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
+//! To match the paper, the top of the stack is at the beginning / on the left.
+//!
+//! There are two important operations on pattern-stacks necessary to understand the algorithm:
+//!     1. We can pop a given constructor off the top of a stack. This operation is called
+//!        `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
+//!        `None`) and `p` a pattern-stack.
+//!        If the pattern on top of the stack can cover `c`, this removes the constructor and
+//!        pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
+//!        Otherwise the pattern-stack is discarded.
+//!        This essentially filters those pattern-stacks whose top covers the constructor `c` and
+//!        discards the others.
+//!
+//!        For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
+//!        pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
+//!        `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
+//!        nothing back.
+//!
+//!        This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
+//!        on top of the stack, and we have four cases:
+//!             1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
+//!                  push onto the stack the arguments of this constructor, and return the result:
+//!                     r_1, .., r_a, p_2, .., p_n
+//!             1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
+//!                  return nothing.
+//!             1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
+//!                  arguments (its arity), and return the resulting stack:
+//!                     _, .., _, p_2, .., p_n
+//!             1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
+//!                  stack:
+//!                     S(c, (r_1, p_2, .., p_n))
+//!                     S(c, (r_2, p_2, .., p_n))
+//!
+//!     2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
+//!        a pattern-stack.
+//!        This is used when we know there are missing constructor cases, but there might be
+//!        existing wildcard patterns, so to check the usefulness of the matrix, we have to check
+//!        all its *other* components.
+//!
+//!        It is computed as follows. We look at the pattern `p_1` on top of the stack,
+//!        and we have three cases:
+//!             1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
+//!             1.2. `p_1 = _`. We return the rest of the stack:
+//!                     p_2, .., p_n
+//!             1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
+//!               stack.
+//!                     D((r_1, p_2, .., p_n))
+//!                     D((r_2, p_2, .., p_n))
+//!
+//!     Note that the OR-patterns are not always used directly in Rust, but are used to derive the
+//!     exhaustive integer matching rules, so they're written here for posterity.
+//!
+//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
+//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
+//! the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
+//!
+//!
+//! The algorithm for computing `U`
+//! -------------------------------
+//! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
+//! That means we're going to check the components from left-to-right, so the algorithm
+//! operates principally on the first component of the matrix and new pattern-stack `p`.
+//! This algorithm is realised in the `is_useful` function.
+//!
+//! Base case. (`n = 0`, i.e., an empty tuple pattern)
+//!     - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
+//!       then `U(P, p)` is false.
+//!     - Otherwise, `P` must be empty, so `U(P, p)` is true.
+//!
+//! Inductive step. (`n > 0`, i.e., whether there's at least one column
+//!                  [which may then be expanded into further columns later])
+//!     We're going to match on the top of the new pattern-stack, `p_1`.
+//!         - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
+//!           Then, the usefulness of `p_1` can be reduced to whether it is useful when
+//!           we ignore all the patterns in the first column of `P` that involve other constructors.
+//!           This is where `S(c, P)` comes in:
+//!           `U(P, p) := U(S(c, P), S(c, p))`
+//!           This special case is handled in `is_useful_specialized`.
+//!
+//!           For example, if `P` is:
+//!           [
+//!               [Some(true), _],
+//!               [None, 0],
+//!           ]
+//!           and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
+//!           matches values that row 2 doesn't. For row 1 however, we need to dig into the
+//!           arguments of `Some` to know whether some new value is covered. So we compute
+//!           `U([[true, _]], [false, 0])`.
+//!
+//!         - If `p_1 == _`, then we look at the list of constructors that appear in the first
+//!               component of the rows of `P`:
+//!             + If there are some constructors that aren't present, then we might think that the
+//!               wildcard `_` is useful, since it covers those constructors that weren't covered
+//!               before.
+//!               That's almost correct, but only works if there were no wildcards in those first
+//!               components. So we need to check that `p` is useful with respect to the rows that
+//!               start with a wildcard, if there are any. This is where `D` comes in:
+//!               `U(P, p) := U(D(P), D(p))`
+//!
+//!               For example, if `P` is:
+//!               [
+//!                   [_, true, _],
+//!                   [None, false, 1],
+//!               ]
+//!               and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
+//!               only had row 2, we'd know that `p` is useful. However row 1 starts with a
+//!               wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
+//!
+//!             + Otherwise, all possible constructors (for the relevant type) are present. In this
+//!               case we must check whether the wildcard pattern covers any unmatched value. For
+//!               that, we can think of the `_` pattern as a big OR-pattern that covers all
+//!               possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
+//!               example. The wildcard pattern is useful in this case if it is useful when
+//!               specialized to one of the possible constructors. So we compute:
+//!               `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
+//!
+//!               For example, if `P` is:
+//!               [
+//!                   [Some(true), _],
+//!                   [None, false],
+//!               ]
+//!               and `p` is [_, false], both `None` and `Some` constructors appear in the first
+//!               components of `P`. We will therefore try popping both constructors in turn: we
+//!               compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]],
+//!               [false]) for the `None` constructor. The first case returns true, so we know that
+//!               `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
+//!               before.
+//!
+//!         - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
+//!           `U(P, p) := U(P, (r_1, p_2, .., p_n))
+//!                    || U(P, (r_2, p_2, .., p_n))`
+//!
+//! Modifications to the algorithm
+//! ------------------------------
+//! The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for
+//! example uninhabited types and variable-length slice patterns. These are drawn attention to
+//! throughout the code below. I'll make a quick note here about how exhaustive integer matching is
+//! accounted for, though.
+//!
+//! Exhaustive integer matching
+//! ---------------------------
+//! An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ...
+//! So to support exhaustive integer matching, we can make use of the logic in the paper for
+//! OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because
+//! they are likely gigantic. So we instead treat ranges as constructors of the integers. This means
+//! that we have a constructor *of* constructors (the integers themselves). We then need to work
+//! through all the inductive step rules above, deriving how the ranges would be treated as
+//! OR-patterns, and making sure that they're treated in the same way even when they're ranges.
+//! There are really only four special cases here:
+//! - When we match on a constructor that's actually a range, we have to treat it as if we would
+//!   an OR-pattern.
+//!     + It turns out that we can simply extend the case for single-value patterns in
+//!      `specialize` to either be *equal* to a value constructor, or *contained within* a range
+//!      constructor.
+//!     + When the pattern itself is a range, you just want to tell whether any of the values in
+//!       the pattern range coincide with values in the constructor range, which is precisely
+//!       intersection.
+//!   Since when encountering a range pattern for a value constructor, we also use inclusion, it
+//!   means that whenever the constructor is a value/range and the pattern is also a value/range,
+//!   we can simply use intersection to test usefulness.
+//! - When we're testing for usefulness of a pattern and the pattern's first component is a
+//!   wildcard.
+//!     + If all the constructors appear in the matrix, we have a slight complication. By default,
+//!       the behaviour (i.e., a disjunction over specialised matrices for each constructor) is
+//!       invalid, because we want a disjunction over every *integer* in each range, not just a
+//!       disjunction over every range. This is a bit more tricky to deal with: essentially we need
+//!       to form equivalence classes of subranges of the constructor range for which the behaviour
+//!       of the matrix `P` and new pattern `p` are the same. This is described in more
+//!       detail in `split_grouped_constructors`.
+//!     + If some constructors are missing from the matrix, it turns out we don't need to do
+//!       anything special (because we know none of the integers are actually wildcards: i.e., we
+//!       can't span wildcards using ranges).
 use self::Constructor::*;
 use self::SliceKind::*;
 use self::Usefulness::*;
diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
index 46b687d76e5..087c2c064cf 100644
--- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs
+++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
@@ -130,6 +130,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                     traits::NonStructuralMatchTy::Generator => {
                         "generators cannot be used in patterns".to_string()
                     }
+                    traits::NonStructuralMatchTy::Closure => {
+                        "closures cannot be used in patterns".to_string()
+                    }
                     traits::NonStructuralMatchTy::Param => {
                         bug!("use of a constant whose type is a parameter inside a pattern")
                     }
diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs
index c0fb84e741f..f2c9f8055b9 100644
--- a/src/librustc_span/hygiene.rs
+++ b/src/librustc_span/hygiene.rs
@@ -822,7 +822,15 @@ pub enum DesugaringKind {
     OpaqueTy,
     Async,
     Await,
-    ForLoop,
+    ForLoop(ForLoopLoc),
+    Operator,
+}
+
+/// 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 +843,8 @@ impl DesugaringKind {
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
-            DesugaringKind::ForLoop => "`for` loop",
+            DesugaringKind::ForLoop(_) => "`for` loop",
+            DesugaringKind::Operator => "operator",
         }
     }
 }
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index 96240066834..af9b5a264e3 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -31,7 +31,9 @@ pub mod edition;
 use edition::Edition;
 pub mod hygiene;
 use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext};
+pub use hygiene::{
+    DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind, SyntaxContext,
+};
 pub mod def_id;
 use def_id::{CrateNum, DefId, LOCAL_CRATE};
 mod span_encoding;
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index fea5880f01e..fdeb58b7b7a 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -227,6 +227,7 @@ symbols! {
         const_loop,
         const_mut_refs,
         const_panic,
+        const_precise_live_drops,
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
         const_transmute,
diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs
index e59fbd313c8..c4deb639140 100644
--- a/src/librustc_trait_selection/traits/structural_match.rs
+++ b/src/librustc_trait_selection/traits/structural_match.rs
@@ -18,6 +18,7 @@ pub enum NonStructuralMatchTy<'tcx> {
     Opaque,
     Generator,
     Projection,
+    Closure,
 }
 
 /// This method traverses the structure of `ty`, trying to find an
@@ -162,6 +163,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
                 self.found = Some(NonStructuralMatchTy::Generator);
                 return true; // Stop visiting.
             }
+            ty::Closure(..) => {
+                self.found = Some(NonStructuralMatchTy::Closure);
+                return true; // Stop visiting.
+            }
             ty::RawPtr(..) => {
                 // structural-match ignores substructure of
                 // `*const _`/`*mut _`, so skip `super_visit_with`.
@@ -211,7 +216,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
                 ty.super_visit_with(self);
                 return false;
             }
-            ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
+            ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
             }
             ty::Error => {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index a2e6c8793cb..37652330108 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -795,6 +795,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
         // FIXME: do we want to commit to this behavior for param bounds?
+        debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
 
         let bounds =
             self.param_env.caller_bounds.iter().filter_map(|predicate| match predicate.kind() {
@@ -952,7 +953,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         import_ids: import_ids.clone(),
                         kind: TraitCandidate(new_trait_ref),
                     },
-                    true,
+                    false,
                 );
             });
         } else {
diff --git a/src/test/ui/async-await/issue-69446-fnmut-capture.rs b/src/test/ui/async-await/issue-69446-fnmut-capture.rs
new file mode 100644
index 00000000000..842115538c9
--- /dev/null
+++ b/src/test/ui/async-await/issue-69446-fnmut-capture.rs
@@ -0,0 +1,22 @@
+// Regression test for issue #69446 - we should display
+// which variable is captured
+// edition:2018
+
+use core::future::Future;
+
+struct Foo;
+impl Foo {
+    fn foo(&mut self) {}
+}
+
+async fn bar<T>(_: impl FnMut() -> T)
+where
+    T: Future<Output = ()>,
+{}
+
+fn main() {
+    let mut x = Foo;
+    bar(move || async { //~ ERROR captured
+        x.foo();
+    });
+}
diff --git a/src/test/ui/async-await/issue-69446-fnmut-capture.stderr b/src/test/ui/async-await/issue-69446-fnmut-capture.stderr
new file mode 100644
index 00000000000..3d2b0402bc5
--- /dev/null
+++ b/src/test/ui/async-await/issue-69446-fnmut-capture.stderr
@@ -0,0 +1,19 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-69446-fnmut-capture.rs:19:17
+   |
+LL |       let mut x = Foo;
+   |           ----- variable defined here
+LL |       bar(move || async {
+   |  _______________-_^
+   | |               |
+   | |               inferred to be a `FnMut` closure
+LL | |         x.foo();
+   | |         - variable captured here
+LL | |     });
+   | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
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-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
index 075e0e2e451..4144d70cc16 100644
--- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
@@ -21,10 +21,13 @@ LL |                    *y = 1;
 error: captured variable cannot escape `FnMut` closure body
   --> $DIR/borrowck-describe-lvalue.rs:264:16
    |
+LL |           let mut x = 0;
+   |               ----- variable defined here
 LL |              || {
    |               - inferred to be a `FnMut` closure
 LL | /                || {
 LL | |                    let y = &mut x;
+   | |                                 - variable captured here
 LL | |                    &mut x;
 LL | |                    *y = 1;
 LL | |                    drop(y);
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/consts/control-flow/drop-fail.precise.stderr b/src/test/ui/consts/control-flow/drop-fail.precise.stderr
new file mode 100644
index 00000000000..b4b6be8a1e5
--- /dev/null
+++ b/src/test/ui/consts/control-flow/drop-fail.precise.stderr
@@ -0,0 +1,15 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-fail.rs:10:9
+   |
+LL |     let x = Some(Vec::new());
+   |         ^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-fail.rs:41:9
+   |
+LL |     let mut tmp = None;
+   |         ^^^^^^^ constants cannot evaluate destructors
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/control-flow/drop-failure.rs b/src/test/ui/consts/control-flow/drop-fail.rs
index 9da5546976c..7bd36726cea 100644
--- a/src/test/ui/consts/control-flow/drop-failure.rs
+++ b/src/test/ui/consts/control-flow/drop-fail.rs
@@ -1,11 +1,14 @@
+// revisions: stock precise
+
 #![feature(const_if_match)]
 #![feature(const_loop)]
+#![cfg_attr(precise, feature(const_precise_live_drops))]
 
-// `x` is *not* always moved into the final value may be dropped inside the initializer.
+// `x` is *not* always moved into the final value and may be dropped inside the initializer.
 const _: Option<Vec<i32>> = {
     let y: Option<Vec<i32>> = None;
     let x = Some(Vec::new());
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock,precise]~^ ERROR destructors cannot be evaluated at compile-time
 
     if true {
         x
@@ -18,7 +21,7 @@ const _: Option<Vec<i32>> = {
 // existing analysis.
 const _: Vec<i32> = {
     let vec_tuple = (Vec::new(),);
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock]~^ ERROR destructors cannot be evaluated at compile-time
 
     vec_tuple.0
 };
@@ -26,7 +29,7 @@ const _: Vec<i32> = {
 // This applies to single-field enum variants as well.
 const _: Vec<i32> = {
     let x: Result<_, Vec<i32>> = Ok(Vec::new());
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock]~^ ERROR destructors cannot be evaluated at compile-time
 
     match x {
         Ok(x) | Err(x) => x,
@@ -36,7 +39,7 @@ const _: Vec<i32> = {
 const _: Option<Vec<i32>> = {
     let mut some = Some(Vec::new());
     let mut tmp = None;
-    //~^ ERROR destructors cannot be evaluated at compile-time
+    //[stock,precise]~^ ERROR destructors cannot be evaluated at compile-time
 
     let mut i = 0;
     while i < 10 {
diff --git a/src/test/ui/consts/control-flow/drop-failure.stderr b/src/test/ui/consts/control-flow/drop-fail.stock.stderr
index 3eec3a929a0..77cded5c438 100644
--- a/src/test/ui/consts/control-flow/drop-failure.stderr
+++ b/src/test/ui/consts/control-flow/drop-fail.stock.stderr
@@ -1,23 +1,23 @@
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:7:9
+  --> $DIR/drop-fail.rs:10:9
    |
 LL |     let x = Some(Vec::new());
    |         ^ constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:20:9
+  --> $DIR/drop-fail.rs:23:9
    |
 LL |     let vec_tuple = (Vec::new(),);
    |         ^^^^^^^^^ constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:28:9
+  --> $DIR/drop-fail.rs:31:9
    |
 LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
    |         ^ constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:38:9
+  --> $DIR/drop-fail.rs:41:9
    |
 LL |     let mut tmp = None;
    |         ^^^^^^^ constants cannot evaluate destructors
diff --git a/src/test/ui/consts/control-flow/drop-success.rs b/src/test/ui/consts/control-flow/drop-pass.rs
index 185d6b63996..b0afd76c4e6 100644
--- a/src/test/ui/consts/control-flow/drop-success.rs
+++ b/src/test/ui/consts/control-flow/drop-pass.rs
@@ -1,7 +1,9 @@
 // run-pass
+// revisions: stock precise
 
 #![feature(const_if_match)]
 #![feature(const_loop)]
+#![cfg_attr(precise, feature(const_precise_live_drops))]
 
 // `x` is always moved into the final value and is not dropped inside the initializer.
 const _: Option<Vec<i32>> = {
diff --git a/src/test/ui/consts/control-flow/drop-precise.rs b/src/test/ui/consts/control-flow/drop-precise.rs
new file mode 100644
index 00000000000..95df76d9905
--- /dev/null
+++ b/src/test/ui/consts/control-flow/drop-precise.rs
@@ -0,0 +1,20 @@
+// run-pass
+// gate-test-const_precise_live_drops
+
+#![feature(const_if_match)]
+#![feature(const_loop)]
+#![feature(const_precise_live_drops)]
+
+const _: Vec<i32> = {
+    let vec_tuple = (Vec::new(),);
+    vec_tuple.0
+};
+
+const _: Vec<i32> = {
+    let x: Result<_, Vec<i32>> = Ok(Vec::new());
+    match x {
+        Ok(x) | Err(x) => x,
+    }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
index 65fc49c0b27..064dc6c262c 100644
--- a/src/test/ui/consts/miri_unleashed/ptr_arith.rs
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
@@ -6,14 +6,15 @@
 
 static CMP: () = {
     let x = &0 as *const _;
-    let _v = x == x;
+    let _v = x == x; //~ NOTE in this
     //~^ ERROR could not evaluate static initializer
     //~| NOTE pointer arithmetic or comparison
+    //~| NOTE in this
 };
 
 static INT_PTR_ARITH: () = unsafe {
     let x: usize = std::mem::transmute(&0);
-    let _v = x + 0;
+    let _v = x + 0; //~ NOTE in this
     //~^ ERROR could not evaluate static initializer
     //~| NOTE pointer-to-integer cast
 };
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
index 805ba9c6b03..4b3fe995700 100644
--- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -5,7 +5,7 @@ LL |     let _v = x == x;
    |              ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:16:14
+  --> $DIR/ptr_arith.rs:17:14
    |
 LL |     let _v = x + 0;
    |              ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
@@ -18,7 +18,7 @@ help: skipping check for `const_compare_raw_pointers` feature
 LL |     let _v = x == x;
    |              ^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/ptr_arith.rs:15:20
+  --> $DIR/ptr_arith.rs:16:20
    |
 LL |     let x: usize = std::mem::transmute(&0);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout
index acd852103ca..fc5ed724e3c 100644
--- a/src/test/ui/hygiene/unpretty-debug.stdout
+++ b/src/test/ui/hygiene/unpretty-debug.stdout
@@ -18,8 +18,12 @@ fn y /* 0#0 */() { }
 Expansions:
 0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
 1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo")
+2: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
+3: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
 
 SyntaxContexts:
 #0: parent: #0, outer_mark: (ExpnId(0), Opaque)
 #1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent)
+#2: parent: #1, outer_mark: (ExpnId(2), Transparent)
+#3: parent: #1, outer_mark: (ExpnId(3), Transparent)
 */
diff --git a/src/test/ui/impl-trait-in-bindings-issue-73003.rs b/src/test/ui/impl-trait-in-bindings-issue-73003.rs
new file mode 100644
index 00000000000..fd8fe5f48df
--- /dev/null
+++ b/src/test/ui/impl-trait-in-bindings-issue-73003.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+#![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete
+
+const _: impl Fn() = ||();
+
+fn main() {}
diff --git a/src/test/ui/impl-trait-in-bindings-issue-73003.stderr b/src/test/ui/impl-trait-in-bindings-issue-73003.stderr
new file mode 100644
index 00000000000..715671c8add
--- /dev/null
+++ b/src/test/ui/impl-trait-in-bindings-issue-73003.stderr
@@ -0,0 +1,11 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/impl-trait-in-bindings-issue-73003.rs:3:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
+
+warning: 1 warning emitted
+
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-40510-1.stderr b/src/test/ui/issues/issue-40510-1.stderr
index f4fda0abc20..54df40b6e3d 100644
--- a/src/test/ui/issues/issue-40510-1.stderr
+++ b/src/test/ui/issues/issue-40510-1.stderr
@@ -1,10 +1,16 @@
 error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-40510-1.rs:7:9
    |
+LL |     let mut x: Box<()> = Box::new(());
+   |         ----- variable defined here
+LL | 
 LL |     || {
    |      - inferred to be a `FnMut` closure
 LL |         &mut x
-   |         ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |         ^^^^^-
+   |         |    |
+   |         |    variable captured here
+   |         returns a reference to a captured variable which escapes the closure body
    |
    = note: `FnMut` closures only have access to their captured variables while they are executing...
    = note: ...therefore, they cannot allow references to captured variables to escape
diff --git a/src/test/ui/issues/issue-40510-3.stderr b/src/test/ui/issues/issue-40510-3.stderr
index 4bc7d0f5dea..cb885ec7d95 100644
--- a/src/test/ui/issues/issue-40510-3.stderr
+++ b/src/test/ui/issues/issue-40510-3.stderr
@@ -1,10 +1,14 @@
 error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-40510-3.rs:7:9
    |
+LL |       let mut x: Vec<()> = Vec::new();
+   |           ----- variable defined here
+LL | 
 LL |       || {
    |        - inferred to be a `FnMut` closure
 LL | /         || {
 LL | |             x.push(())
+   | |             - variable captured here
 LL | |         }
    | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |
diff --git a/src/test/ui/issues/issue-49824.stderr b/src/test/ui/issues/issue-49824.stderr
index 6b486aafcdf..2fec482543d 100644
--- a/src/test/ui/issues/issue-49824.stderr
+++ b/src/test/ui/issues/issue-49824.stderr
@@ -1,11 +1,14 @@
 error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-49824.rs:4:9
    |
+LL |       let mut x = 0;
+   |           ----- variable defined here
 LL |       || {
    |        - inferred to be a `FnMut` closure
 LL | /         || {
 LL | |
 LL | |             let _y = &mut x;
+   | |                           - variable captured here
 LL | |         }
    | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
    |
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/nll/issue-53040.stderr b/src/test/ui/nll/issue-53040.stderr
index 7cba32c6743..87ffe9b1abf 100644
--- a/src/test/ui/nll/issue-53040.stderr
+++ b/src/test/ui/nll/issue-53040.stderr
@@ -1,9 +1,13 @@
 error: captured variable cannot escape `FnMut` closure body
   --> $DIR/issue-53040.rs:3:8
    |
+LL |     let mut v: Vec<()> = Vec::new();
+   |         ----- variable defined here
 LL |     || &mut v;
-   |      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
-   |      |
+   |      - ^^^^^-
+   |      | |    |
+   |      | |    variable captured here
+   |      | returns a reference to a captured variable which escapes the closure body
    |      inferred to be a `FnMut` closure
    |
    = note: `FnMut` closures only have access to their captured variables while they are executing...
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/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
index 4c275b19492..b087e03b464 100644
--- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
+++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
@@ -1,9 +1,13 @@
 error: captured variable cannot escape `FnMut` closure body
   --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
    |
+LL |         let mut x = 0;
+   |             ----- variable defined here
 LL |         let mut f = || &mut x;
-   |                      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
-   |                      |
+   |                      - ^^^^^-
+   |                      | |    |
+   |                      | |    variable captured here
+   |                      | returns a reference to a captured variable which escapes the closure body
    |                      inferred to be a `FnMut` closure
    |
    = note: `FnMut` closures only have access to their captured variables while they are executing...
diff --git a/src/test/ui/traits/trait-alias/issue-60021-assoc-method-resolve.rs b/src/test/ui/traits/trait-alias/issue-60021-assoc-method-resolve.rs
new file mode 100644
index 00000000000..5e27ed3c646
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/issue-60021-assoc-method-resolve.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+trait SomeTrait {
+    fn map(&self) {}
+}
+
+impl<T> SomeTrait for Option<T> {}
+
+trait SomeAlias = SomeTrait;
+
+fn main() {
+    let x = Some(123);
+    // This should resolve to the trait impl for Option
+    Option::map(x, |z| z);
+    // This should resolve to the trait impl for SomeTrait
+    SomeTrait::map(&x);
+}
diff --git a/src/test/ui/traits/trait-alias/issue-72415-assoc-const-resolve.rs b/src/test/ui/traits/trait-alias/issue-72415-assoc-const-resolve.rs
new file mode 100644
index 00000000000..e49125d1024
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/issue-72415-assoc-const-resolve.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+trait Bounded { const MAX: Self; }
+
+impl Bounded for u32 {
+    // This should correctly resolve to the associated const in the inherent impl of u32.
+    const MAX: Self = u32::MAX;
+}
+
+trait Num = Bounded + Copy;
+
+fn main() {}
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..7e9c8559a4b 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 this method call
 LL | 
 LL |     x.clone();
    |     ^ value borrowed here after move
    |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $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