diff --git a/src/doc/unstable-book/src/compiler-flags/self-profile.md b/src/doc/unstable-book/src/compiler-flags/self-profile.md
index 6de1c774f7cd7..7305141a42714 100644
--- a/src/doc/unstable-book/src/compiler-flags/self-profile.md
+++ b/src/doc/unstable-book/src/compiler-flags/self-profile.md
@@ -13,7 +13,7 @@ For example:
 First, run a compilation session and provide the `-Zself-profile` flag:
 
 ```console
-$ rustc --crate-name foo -Zself-profile`
+$ rustc --crate-name foo -Zself-profile
 ```
 
 This will generate three files in the working directory such as:
diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs
index 00a171e6b5fb1..abf461338d80a 100644
--- a/src/libcore/future/future.rs
+++ b/src/libcore/future/future.rs
@@ -27,6 +27,7 @@ use crate::task::{Context, Poll};
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[lang = "future_trait"]
+#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
 pub trait Future {
     /// The type of value produced on completion.
     #[stable(feature = "futures_api", since = "1.36.0")]
diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs
index e23e2f2c1306f..bb7d59e113c08 100644
--- a/src/libprofiler_builtins/build.rs
+++ b/src/libprofiler_builtins/build.rs
@@ -24,6 +24,12 @@ fn main() {
         "InstrProfilingUtil.c",
         "InstrProfilingValue.c",
         "InstrProfilingWriter.c",
+        // This file was renamed in LLVM 10.
+        "InstrProfilingRuntime.cc",
+        "InstrProfilingRuntime.cpp",
+        // These files were added in LLVM 11.
+        "InstrProfilingInternal.c",
+        "InstrProfilingBiasVar.c",
     ];
 
     if target.contains("msvc") {
@@ -69,14 +75,12 @@ fn main() {
 
     let src_root = root.join("lib").join("profile");
     for src in profile_sources {
-        cfg.file(src_root.join(src));
+        let path = src_root.join(src);
+        if path.exists() {
+            cfg.file(path);
+        }
     }
 
-    // The file was renamed in LLVM 10.
-    let old_runtime_path = src_root.join("InstrProfilingRuntime.cc");
-    let new_runtime_path = src_root.join("InstrProfilingRuntime.cpp");
-    cfg.file(if old_runtime_path.exists() { old_runtime_path } else { new_runtime_path });
-
     cfg.include(root.join("include"));
     cfg.warnings(false);
     cfg.compile("profiler-rt");
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index d2c4478ccfeb6..90a3a5ec64e0e 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
+use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_target::asm;
 use std::collections::hash_map::Entry;
@@ -1361,9 +1361,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Block,
         opt_label: Option<Label>,
     ) -> hir::Expr<'hir> {
+        let orig_head_span = head.span;
         // expand <head>
         let mut head = self.lower_expr_mut(head);
-        let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
+        let desugared_span = self.mark_span_with_reason(
+            DesugaringKind::ForLoop(ForLoopLoc::Head),
+            orig_head_span,
+            None,
+        );
         head.span = desugared_span;
 
         let iter = Ident::with_dummy_span(sym::iter);
@@ -1458,10 +1463,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `mut iter => { ... }`
         let iter_arm = self.arm(iter_pat, loop_expr);
 
+        let into_iter_span = self.mark_span_with_reason(
+            DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
+            orig_head_span,
+            None,
+        );
+
         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
         let into_iter_expr = {
             let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
-            self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head])
+            self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
         };
 
         let match_expr = self.arena.alloc(self.expr_match(
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index d3e3441b087c2..9764c9a102e8a 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -797,6 +797,7 @@ pub unsafe fn optimize_thin_module(
         kind: ModuleKind::Regular,
     };
     {
+        let target = &*module.module_llvm.tm;
         let llmod = module.module_llvm.llmod();
         save_temp_bitcode(&cgcx, &module, "thin-lto-input");
 
@@ -833,7 +834,7 @@ pub unsafe fn optimize_thin_module(
         {
             let _timer =
                 cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
-            if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) {
+            if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
                 let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg));
             }
@@ -865,7 +866,7 @@ pub unsafe fn optimize_thin_module(
         {
             let _timer =
                 cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
-            if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
+            if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) {
                 let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg));
             }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 8063d97aa73a9..7beb4fc897472 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -233,6 +233,8 @@ pub enum TypeKind {
     Metadata = 14,
     X86_MMX = 15,
     Token = 16,
+    ScalableVector = 17,
+    BFloat = 18,
 }
 
 impl TypeKind {
@@ -255,6 +257,8 @@ impl TypeKind {
             TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata,
             TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX,
             TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token,
+            TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector,
+            TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat,
         }
     }
 }
@@ -2141,10 +2145,18 @@ extern "C" {
         PreservedSymbols: *const *const c_char,
         PreservedSymbolsLen: c_uint,
     ) -> Option<&'static mut ThinLTOData>;
-    pub fn LLVMRustPrepareThinLTORename(Data: &ThinLTOData, Module: &Module) -> bool;
+    pub fn LLVMRustPrepareThinLTORename(
+        Data: &ThinLTOData,
+        Module: &Module,
+        Target: &TargetMachine,
+    ) -> bool;
     pub fn LLVMRustPrepareThinLTOResolveWeak(Data: &ThinLTOData, Module: &Module) -> bool;
     pub fn LLVMRustPrepareThinLTOInternalize(Data: &ThinLTOData, Module: &Module) -> bool;
-    pub fn LLVMRustPrepareThinLTOImport(Data: &ThinLTOData, Module: &Module) -> bool;
+    pub fn LLVMRustPrepareThinLTOImport(
+        Data: &ThinLTOData,
+        Module: &Module,
+        Target: &TargetMachine,
+    ) -> bool;
     pub fn LLVMRustGetThinLTOModuleImports(
         Data: *const ThinLTOData,
         ModuleNameCallback: ThinLTOModuleNameCallback,
diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs
index 0d0321ec4ae5e..432b2f3bdc3c1 100644
--- a/src/librustc_codegen_ssa/common.rs
+++ b/src/librustc_codegen_ssa/common.rs
@@ -98,6 +98,8 @@ pub enum TypeKind {
     Metadata,
     X86_MMX,
     Token,
+    ScalableVector,
+    BFloat,
 }
 
 // FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
diff --git a/src/librustc_errors/json.rs b/src/librustc_errors/json.rs
index 1382825922b0e..24186198fd2b1 100644
--- a/src/librustc_errors/json.rs
+++ b/src/librustc_errors/json.rs
@@ -36,6 +36,7 @@ pub struct JsonEmitter {
     pretty: bool,
     ui_testing: bool,
     json_rendered: HumanReadableErrorType,
+    terminal_width: Option<usize>,
     macro_backtrace: bool,
 }
 
@@ -45,6 +46,7 @@ impl JsonEmitter {
         source_map: Lrc<SourceMap>,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        terminal_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
@@ -54,6 +56,7 @@ impl JsonEmitter {
             pretty,
             ui_testing: false,
             json_rendered,
+            terminal_width,
             macro_backtrace,
         }
     }
@@ -61,6 +64,7 @@ impl JsonEmitter {
     pub fn basic(
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        terminal_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
@@ -69,6 +73,7 @@ impl JsonEmitter {
             Lrc::new(SourceMap::new(file_path_mapping)),
             pretty,
             json_rendered,
+            terminal_width,
             macro_backtrace,
         )
     }
@@ -79,6 +84,7 @@ impl JsonEmitter {
         source_map: Lrc<SourceMap>,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        terminal_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
@@ -88,6 +94,7 @@ impl JsonEmitter {
             pretty,
             ui_testing: false,
             json_rendered,
+            terminal_width,
             macro_backtrace,
         }
     }
@@ -247,7 +254,13 @@ impl Diagnostic {
         let buf = BufWriter::default();
         let output = buf.clone();
         je.json_rendered
-            .new_emitter(Box::new(buf), Some(je.sm.clone()), false, None, je.macro_backtrace)
+            .new_emitter(
+                Box::new(buf),
+                Some(je.sm.clone()),
+                false,
+                je.terminal_width,
+                je.macro_backtrace,
+            )
             .ui_testing(je.ui_testing)
             .emit_diagnostic(diag);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs
index cd6f034f7a5da..5aaf219b315bd 100644
--- a/src/librustc_hir/lang_items.rs
+++ b/src/librustc_hir/lang_items.rs
@@ -21,11 +21,26 @@ use rustc_span::Span;
 
 use lazy_static::lazy_static;
 
+pub enum LangItemGroup {
+    Op,
+}
+
+const NUM_GROUPS: usize = 1;
+
+macro_rules! expand_group {
+    () => {
+        None
+    };
+    ($group:expr) => {
+        Some($group)
+    };
+}
+
 // The actual lang items defined come at the end of this file in one handy table.
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
     (
-        $( $variant:ident, $name:expr, $method:ident, $target:expr; )*
+        $( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
     ) => {
 
         enum_from_u32! {
@@ -45,6 +60,13 @@ macro_rules! language_item_table {
                     $( $variant => $name, )*
                 }
             }
+
+            pub fn group(self) -> Option<LangItemGroup> {
+                use LangItemGroup::*;
+                match self {
+                    $( $variant => expand_group!($($group)*), )*
+                }
+            }
         }
 
         #[derive(HashStable_Generic)]
@@ -54,6 +76,9 @@ macro_rules! language_item_table {
             pub items: Vec<Option<DefId>>,
             /// Lang items that were not found during collection.
             pub missing: Vec<LangItem>,
+            /// Mapping from `LangItemGroup` discriminants to all
+            /// `DefId`s of lang items in that group.
+            pub groups: [Vec<DefId>; NUM_GROUPS],
         }
 
         impl LanguageItems {
@@ -64,6 +89,7 @@ macro_rules! language_item_table {
                 Self {
                     items: vec![$(init_none($variant)),*],
                     missing: Vec::new(),
+                    groups: [vec![]; NUM_GROUPS],
                 }
             }
 
@@ -79,6 +105,10 @@ macro_rules! language_item_table {
                 self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
             }
 
+            pub fn group(&self, group: LangItemGroup) -> &[DefId] {
+                self.groups[group as usize].as_ref()
+            }
+
             $(
                 /// Returns the corresponding `DefId` for the lang item
                 #[doc = $name]
@@ -171,30 +201,30 @@ language_item_table! {
     CoerceUnsizedTraitLangItem,  "coerce_unsized",     coerce_unsized_trait,    Target::Trait;
     DispatchFromDynTraitLangItem,"dispatch_from_dyn",  dispatch_from_dyn_trait, Target::Trait;
 
-    AddTraitLangItem,            "add",                add_trait,               Target::Trait;
-    SubTraitLangItem,            "sub",                sub_trait,               Target::Trait;
-    MulTraitLangItem,            "mul",                mul_trait,               Target::Trait;
-    DivTraitLangItem,            "div",                div_trait,               Target::Trait;
-    RemTraitLangItem,            "rem",                rem_trait,               Target::Trait;
-    NegTraitLangItem,            "neg",                neg_trait,               Target::Trait;
-    NotTraitLangItem,            "not",                not_trait,               Target::Trait;
-    BitXorTraitLangItem,         "bitxor",             bitxor_trait,            Target::Trait;
-    BitAndTraitLangItem,         "bitand",             bitand_trait,            Target::Trait;
-    BitOrTraitLangItem,          "bitor",              bitor_trait,             Target::Trait;
-    ShlTraitLangItem,            "shl",                shl_trait,               Target::Trait;
-    ShrTraitLangItem,            "shr",                shr_trait,               Target::Trait;
-    AddAssignTraitLangItem,      "add_assign",         add_assign_trait,        Target::Trait;
-    SubAssignTraitLangItem,      "sub_assign",         sub_assign_trait,        Target::Trait;
-    MulAssignTraitLangItem,      "mul_assign",         mul_assign_trait,        Target::Trait;
-    DivAssignTraitLangItem,      "div_assign",         div_assign_trait,        Target::Trait;
-    RemAssignTraitLangItem,      "rem_assign",         rem_assign_trait,        Target::Trait;
-    BitXorAssignTraitLangItem,   "bitxor_assign",      bitxor_assign_trait,     Target::Trait;
-    BitAndAssignTraitLangItem,   "bitand_assign",      bitand_assign_trait,     Target::Trait;
-    BitOrAssignTraitLangItem,    "bitor_assign",       bitor_assign_trait,      Target::Trait;
-    ShlAssignTraitLangItem,      "shl_assign",         shl_assign_trait,        Target::Trait;
-    ShrAssignTraitLangItem,      "shr_assign",         shr_assign_trait,        Target::Trait;
-    IndexTraitLangItem,          "index",              index_trait,             Target::Trait;
-    IndexMutTraitLangItem,       "index_mut",          index_mut_trait,         Target::Trait;
+    AddTraitLangItem(Op),        "add",                add_trait,               Target::Trait;
+    SubTraitLangItem(Op),        "sub",                sub_trait,               Target::Trait;
+    MulTraitLangItem(Op),        "mul",                mul_trait,               Target::Trait;
+    DivTraitLangItem(Op),        "div",                div_trait,               Target::Trait;
+    RemTraitLangItem(Op),        "rem",                rem_trait,               Target::Trait;
+    NegTraitLangItem(Op),        "neg",                neg_trait,               Target::Trait;
+    NotTraitLangItem(Op),        "not",                not_trait,               Target::Trait;
+    BitXorTraitLangItem(Op),     "bitxor",             bitxor_trait,            Target::Trait;
+    BitAndTraitLangItem(Op),     "bitand",             bitand_trait,            Target::Trait;
+    BitOrTraitLangItem(Op),      "bitor",              bitor_trait,             Target::Trait;
+    ShlTraitLangItem(Op),        "shl",                shl_trait,               Target::Trait;
+    ShrTraitLangItem(Op),        "shr",                shr_trait,               Target::Trait;
+    AddAssignTraitLangItem(Op),  "add_assign",         add_assign_trait,        Target::Trait;
+    SubAssignTraitLangItem(Op),  "sub_assign",         sub_assign_trait,        Target::Trait;
+    MulAssignTraitLangItem(Op),  "mul_assign",         mul_assign_trait,        Target::Trait;
+    DivAssignTraitLangItem(Op),  "div_assign",         div_assign_trait,        Target::Trait;
+    RemAssignTraitLangItem(Op),  "rem_assign",         rem_assign_trait,        Target::Trait;
+    BitXorAssignTraitLangItem(Op),"bitxor_assign",     bitxor_assign_trait,     Target::Trait;
+    BitAndAssignTraitLangItem(Op),"bitand_assign",     bitand_assign_trait,     Target::Trait;
+    BitOrAssignTraitLangItem(Op),"bitor_assign",       bitor_assign_trait,      Target::Trait;
+    ShlAssignTraitLangItem(Op),  "shl_assign",         shl_assign_trait,        Target::Trait;
+    ShrAssignTraitLangItem(Op),  "shr_assign",         shr_assign_trait,        Target::Trait;
+    IndexTraitLangItem(Op),      "index",              index_trait,             Target::Trait;
+    IndexMutTraitLangItem(Op),   "index_mut",          index_mut_trait,         Target::Trait;
 
     UnsafeCellTypeLangItem,      "unsafe_cell",        unsafe_cell_type,        Target::Struct;
     VaListTypeLangItem,          "va_list",            va_list,                 Target::Struct;
diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs
index 04d941fb8a7c4..1687bcc155636 100644
--- a/src/librustc_infer/infer/error_reporting/need_type_info.rs
+++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs
@@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let msg = if let Some(simple_ident) = pattern.simple_ident() {
                 match pattern.span.desugaring_kind() {
                     None => format!("consider giving `{}` {}", simple_ident, suffix),
-                    Some(DesugaringKind::ForLoop) => {
+                    Some(DesugaringKind::ForLoop(_)) => {
                         "the element type for this iterator is not specified".to_string()
                     }
                     _ => format!("this needs {}", suffix),
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
index 6677c0e59f63a..20617bb8bd8fc 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -28,30 +28,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         br: &ty::BoundRegion,
     ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> {
         if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
-            let def_id = anon_reg.def_id;
-            if let Some(def_id) = def_id.as_local() {
-                let hir_id = self.tcx().hir().as_local_hir_id(def_id);
-                let fndecl = match self.tcx().hir().get(hir_id) {
-                    Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
-                    | Node::TraitItem(&hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(ref m, ..),
-                        ..
-                    })
-                    | Node::ImplItem(&hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(ref m, ..),
-                        ..
-                    }) => &m.decl,
-                    _ => return None,
-                };
+            let hir_id = self.tcx().hir().as_local_hir_id(anon_reg.def_id);
+            let fndecl = match self.tcx().hir().get(hir_id) {
+                Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
+                | Node::TraitItem(&hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(ref m, ..),
+                    ..
+                })
+                | Node::ImplItem(&hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(ref m, ..), ..
+                }) => &m.decl,
+                _ => return None,
+            };
 
-                return fndecl
-                    .inputs
-                    .iter()
-                    .find_map(|arg| self.find_component_for_bound_region(arg, br))
-                    .map(|ty| (ty, &**fndecl));
-            }
+            fndecl
+                .inputs
+                .iter()
+                .find_map(|arg| self.find_component_for_bound_region(arg, br))
+                .map(|ty| (ty, &**fndecl))
+        } else {
+            None
         }
-        None
     }
 
     // This method creates a FindNestedTypeVisitor which returns the type corresponding
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 3012928a09854..72deba990b0b5 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -75,8 +75,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
 
         if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
-            let is_self_anon = self.is_self_anon(is_first, scope_def_id);
-            if is_self_anon {
+            if self.is_self_anon(is_first, scope_def_id) {
                 return None;
             }
 
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 46dad81a099bb..b6e971feb0e5f 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -10,219 +10,217 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the return type is a static impl Trait.
     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
         debug!("try_report_static_impl_trait(error={:?})", self.error);
-        if let Some(ref error) = self.error {
-            if let RegionResolutionError::SubSupConflict(
-                _,
-                var_origin,
-                sub_origin,
-                sub_r,
-                sup_origin,
-                sup_r,
-            ) = error
-            {
-                debug!(
-                    "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
-                    var_origin, sub_origin, sub_r, sup_origin, sup_r
+        if let Some(RegionResolutionError::SubSupConflict(
+            _,
+            var_origin,
+            ref sub_origin,
+            sub_r,
+            ref sup_origin,
+            sup_r,
+        )) = self.error
+        {
+            debug!(
+                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+                var_origin, sub_origin, sub_r, sup_origin, sup_r
+            );
+            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
+            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
+            if fn_returns.is_empty() {
+                return None;
+            }
+            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+            if *sub_r == RegionKind::ReStatic {
+                let sp = var_origin.span();
+                let return_sp = sub_origin.span();
+                let param_info = self.find_param_with_region(sup_r, sub_r)?;
+                let (lifetime_name, lifetime) = if sup_r.has_name() {
+                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+                } else {
+                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
+                };
+                let mut err = struct_span_err!(
+                    self.tcx().sess,
+                    sp,
+                    E0759,
+                    "cannot infer an appropriate lifetime"
                 );
-                let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
-                debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
-                let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
-                if fn_returns.is_empty() {
-                    return None;
-                }
-                debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
-                if **sub_r == RegionKind::ReStatic {
-                    let sp = var_origin.span();
-                    let return_sp = sub_origin.span();
-                    let param_info = self.find_param_with_region(sup_r, sub_r)?;
-                    let (lifetime_name, lifetime) = if sup_r.has_name() {
-                        (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+                err.span_label(
+                    param_info.param_ty_span,
+                    &format!("this data with {}...", lifetime),
+                );
+                debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+
+                // We try to make the output have fewer overlapping spans if possible.
+                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+                    && sup_origin.span() != return_sp
+                {
+                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+
+                    // Customize the spans and labels depending on their relative order so
+                    // that split sentences flow correctly.
+                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+                        // Avoid the following:
+                        //
+                        // error: cannot infer an appropriate lifetime
+                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+                        //    |
+                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+                        //    |           ----                      ---------^-
+                        //
+                        // and instead show:
+                        //
+                        // error: cannot infer an appropriate lifetime
+                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+                        //    |
+                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+                        //    |           ----                               ^
+                        err.span_label(
+                            sup_origin.span(),
+                            "...is captured here, requiring it to live as long as `'static`",
+                        );
                     } else {
-                        ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
-                    };
-                    let mut err = struct_span_err!(
-                        self.tcx().sess,
-                        sp,
-                        E0759,
-                        "cannot infer an appropriate lifetime"
-                    );
+                        err.span_label(sup_origin.span(), "...is captured here...");
+                        if return_sp < sup_origin.span() {
+                            err.span_note(
+                                return_sp,
+                                "...and is required to live as long as `'static` here",
+                            );
+                        } else {
+                            err.span_label(
+                                return_sp,
+                                "...and is required to live as long as `'static` here",
+                            );
+                        }
+                    }
+                } else {
                     err.span_label(
-                        param_info.param_ty_span,
-                        &format!("this data with {}...", lifetime),
+                        return_sp,
+                        "...is captured and required to live as long as `'static` here",
                     );
-                    debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+                }
 
-                    // We try to make the output have fewer overlapping spans if possible.
-                    if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
-                        && sup_origin.span() != return_sp
-                    {
-                        // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+                // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+                let consider = "consider changing the";
+                let declare = "to declare that the";
+                let arg = match param_info.param.pat.simple_ident() {
+                    Some(simple_ident) => format!("argument `{}`", simple_ident),
+                    None => "the argument".to_string(),
+                };
+                let explicit =
+                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+                let explicit_static =
+                    format!("explicit `'static` bound to the lifetime of {}", arg);
+                let captures = format!("captures data from {}", arg);
+                let add_static_bound =
+                    "alternatively, add an explicit `'static` bound to this reference";
+                let plus_lt = format!(" + {}", lifetime_name);
+                for fn_return in fn_returns {
+                    if fn_return.span.desugaring_kind().is_some() {
+                        // Skip `async` desugaring `impl Future`.
+                        continue;
+                    }
+                    match fn_return.kind {
+                        TyKind::OpaqueDef(item_id, _) => {
+                            let item = self.tcx().hir().item(item_id.id);
+                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+                                opaque
+                            } else {
+                                err.emit();
+                                return Some(ErrorReported);
+                            };
 
-                        // Customize the spans and labels depending on their relative order so
-                        // that split sentences flow correctly.
-                        if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
-                            // Avoid the following:
-                            //
-                            // error: cannot infer an appropriate lifetime
-                            //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
-                            //    |
-                            // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-                            //    |           ----                      ---------^-
-                            //
-                            // and instead show:
-                            //
-                            // error: cannot infer an appropriate lifetime
-                            //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
-                            //    |
-                            // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-                            //    |           ----                               ^
-                            err.span_label(
-                                sup_origin.span(),
-                                "...is captured here, requiring it to live as long as `'static`",
-                            );
-                        } else {
-                            err.span_label(sup_origin.span(), "...is captured here...");
-                            if return_sp < sup_origin.span() {
-                                err.span_note(
-                                    return_sp,
-                                    "...and is required to live as long as `'static` here",
+                            if let Some(span) = opaque
+                                .bounds
+                                .iter()
+                                .filter_map(|arg| match arg {
+                                    GenericBound::Outlives(Lifetime {
+                                        name: LifetimeName::Static,
+                                        span,
+                                        ..
+                                    }) => Some(*span),
+                                    _ => None,
+                                })
+                                .next()
+                            {
+                                err.span_suggestion_verbose(
+                                    span,
+                                    &format!("{} `impl Trait`'s {}", consider, explicit_static),
+                                    lifetime_name.clone(),
+                                    Applicability::MaybeIncorrect,
                                 );
+                                err.span_suggestion_verbose(
+                                    param_info.param_ty_span,
+                                    add_static_bound,
+                                    param_info.param_ty.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else if let Some(_) = opaque
+                                .bounds
+                                .iter()
+                                .filter_map(|arg| match arg {
+                                    GenericBound::Outlives(Lifetime { name, span, .. })
+                                        if name.ident().to_string() == lifetime_name =>
+                                    {
+                                        Some(*span)
+                                    }
+                                    _ => None,
+                                })
+                                .next()
+                            {
                             } else {
-                                err.span_label(
-                                    return_sp,
-                                    "...and is required to live as long as `'static` here",
+                                err.span_suggestion_verbose(
+                                    fn_return.span.shrink_to_hi(),
+                                    &format!(
+                                        "{declare} `impl Trait` {captures}, {explicit}",
+                                        declare = declare,
+                                        captures = captures,
+                                        explicit = explicit,
+                                    ),
+                                    plus_lt.clone(),
+                                    Applicability::MaybeIncorrect,
                                 );
                             }
                         }
-                    } else {
-                        err.span_label(
-                            return_sp,
-                            "...is captured and required to live as long as `'static` here",
-                        );
-                    }
-
-                    // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-                    let consider = "consider changing the";
-                    let declare = "to declare that the";
-                    let arg = match param_info.param.pat.simple_ident() {
-                        Some(simple_ident) => format!("argument `{}`", simple_ident),
-                        None => "the argument".to_string(),
-                    };
-                    let explicit =
-                        format!("you can add an explicit `{}` lifetime bound", lifetime_name);
-                    let explicit_static =
-                        format!("explicit `'static` bound to the lifetime of {}", arg);
-                    let captures = format!("captures data from {}", arg);
-                    let add_static_bound =
-                        "alternatively, add an explicit `'static` bound to this reference";
-                    let plus_lt = format!(" + {}", lifetime_name);
-                    for fn_return in fn_returns {
-                        if fn_return.span.desugaring_kind().is_some() {
-                            // Skip `async` desugaring `impl Future`.
-                            continue;
-                        }
-                        match fn_return.kind {
-                            TyKind::OpaqueDef(item_id, _) => {
-                                let item = self.tcx().hir().item(item_id.id);
-                                let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
-                                    opaque
-                                } else {
-                                    err.emit();
-                                    return Some(ErrorReported);
-                                };
-
-                                if let Some(span) = opaque
-                                    .bounds
-                                    .iter()
-                                    .filter_map(|arg| match arg {
-                                        GenericBound::Outlives(Lifetime {
-                                            name: LifetimeName::Static,
-                                            span,
-                                            ..
-                                        }) => Some(*span),
-                                        _ => None,
-                                    })
-                                    .next()
-                                {
-                                    err.span_suggestion_verbose(
-                                        span,
-                                        &format!("{} `impl Trait`'s {}", consider, explicit_static),
-                                        lifetime_name.clone(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                    err.span_suggestion_verbose(
-                                        param_info.param_ty_span,
-                                        add_static_bound,
-                                        param_info.param_ty.to_string(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                } else if let Some(_) = opaque
-                                    .bounds
-                                    .iter()
-                                    .filter_map(|arg| match arg {
-                                        GenericBound::Outlives(Lifetime { name, span, .. })
-                                            if name.ident().to_string() == lifetime_name =>
-                                        {
-                                            Some(*span)
-                                        }
-                                        _ => None,
-                                    })
-                                    .next()
-                                {
-                                } else {
-                                    err.span_suggestion_verbose(
-                                        fn_return.span.shrink_to_hi(),
-                                        &format!(
-                                            "{declare} `impl Trait` {captures}, {explicit}",
-                                            declare = declare,
-                                            captures = captures,
-                                            explicit = explicit,
-                                        ),
-                                        plus_lt.clone(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
+                        TyKind::TraitObject(_, lt) => match lt.name {
+                            LifetimeName::ImplicitObjectLifetimeDefault => {
+                                err.span_suggestion_verbose(
+                                    fn_return.span.shrink_to_hi(),
+                                    &format!(
+                                        "{declare} trait object {captures}, {explicit}",
+                                        declare = declare,
+                                        captures = captures,
+                                        explicit = explicit,
+                                    ),
+                                    plus_lt.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            name if name.ident().to_string() != lifetime_name => {
+                                // With this check we avoid suggesting redundant bounds. This
+                                // would happen if there are nested impl/dyn traits and only
+                                // one of them has the bound we'd suggest already there, like
+                                // in `impl Foo<X = dyn Bar> + '_`.
+                                err.span_suggestion_verbose(
+                                    lt.span,
+                                    &format!("{} trait object's {}", consider, explicit_static),
+                                    lifetime_name.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                err.span_suggestion_verbose(
+                                    param_info.param_ty_span,
+                                    add_static_bound,
+                                    param_info.param_ty.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
                             }
-                            TyKind::TraitObject(_, lt) => match lt.name {
-                                LifetimeName::ImplicitObjectLifetimeDefault => {
-                                    err.span_suggestion_verbose(
-                                        fn_return.span.shrink_to_hi(),
-                                        &format!(
-                                            "{declare} trait object {captures}, {explicit}",
-                                            declare = declare,
-                                            captures = captures,
-                                            explicit = explicit,
-                                        ),
-                                        plus_lt.clone(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                                name if name.ident().to_string() != lifetime_name => {
-                                    // With this check we avoid suggesting redundant bounds. This
-                                    // would happen if there are nested impl/dyn traits and only
-                                    // one of them has the bound we'd suggest already there, like
-                                    // in `impl Foo<X = dyn Bar> + '_`.
-                                    err.span_suggestion_verbose(
-                                        lt.span,
-                                        &format!("{} trait object's {}", consider, explicit_static),
-                                        lifetime_name.clone(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                    err.span_suggestion_verbose(
-                                        param_info.param_ty_span,
-                                        add_static_bound,
-                                        param_info.param_ty.to_string(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                                _ => {}
-                            },
                             _ => {}
-                        }
+                        },
+                        _ => {}
                     }
-                    err.emit();
-                    return Some(ErrorReported);
                 }
+                err.emit();
+                return Some(ErrorReported);
             }
         }
         None
diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
index 22b130cdf5ffe..fa999abb1a86c 100644
--- a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
+++ b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
@@ -3,7 +3,7 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, DefIdTree, Region, Ty};
 use rustc_span::Span;
 
@@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     // FIXME(#42703) - Need to handle certain cases here.
     pub(super) fn is_return_type_anon(
         &self,
-        scope_def_id: DefId,
+        scope_def_id: LocalDefId,
         br: ty::BoundRegion,
         decl: &hir::FnDecl<'_>,
     ) -> Option<Span> {
@@ -112,9 +112,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     // corresponds to self and if yes, we display E0312.
     // FIXME(#42700) - Need to format self properly to
     // enable E0621 for it.
-    pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
+    pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: LocalDefId) -> bool {
         is_first
-            && self.tcx().opt_associated_item(scope_def_id).map(|i| i.fn_has_self_parameter)
+            && self
+                .tcx()
+                .opt_associated_item(scope_def_id.to_def_id())
+                .map(|i| i.fn_has_self_parameter)
                 == Some(true)
     }
 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 814ca627e2cf8..d0275a0dd0dcb 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
 use rustc_middle::mir::interpret::{sign_extend, truncate};
 use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
@@ -525,78 +525,82 @@ enum FfiResult<'tcx> {
     FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
 }
 
-fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    match ty.kind {
-        ty::FnPtr(_) => true,
-        ty::Ref(..) => true,
-        ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
-            for field in field_def.all_fields() {
-                let field_ty =
-                    tcx.normalize_erasing_regions(ParamEnv::reveal_all(), field.ty(tcx, substs));
-                if field_ty.is_zst(tcx, field.did) {
-                    continue;
-                }
+impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
+    /// Is type known to be non-null?
+    fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool {
+        match ty.kind {
+            ty::FnPtr(_) => true,
+            ty::Ref(..) => true,
+            ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
+                for field in field_def.all_fields() {
+                    let field_ty = self.cx.tcx.normalize_erasing_regions(
+                        self.cx.param_env,
+                        field.ty(self.cx.tcx, substs),
+                    );
+                    if field_ty.is_zst(self.cx.tcx, field.did) {
+                        continue;
+                    }
 
-                let attrs = tcx.get_attrs(field_def.did);
-                if attrs.iter().any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
-                    || ty_is_known_nonnull(tcx, field_ty)
-                {
-                    return true;
+                    let attrs = self.cx.tcx.get_attrs(field_def.did);
+                    if attrs
+                        .iter()
+                        .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
+                        || self.ty_is_known_nonnull(field_ty)
+                    {
+                        return true;
+                    }
                 }
-            }
 
-            false
+                false
+            }
+            _ => false,
         }
-        _ => false,
     }
-}
 
-/// Check if this enum can be safely exported based on the
-/// "nullable pointer optimization". Currently restricted
-/// to function pointers, references, core::num::NonZero*,
-/// core::ptr::NonNull, and #[repr(transparent)] newtypes.
-/// FIXME: This duplicates code in codegen.
-fn is_repr_nullable_ptr<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-    ty_def: &'tcx ty::AdtDef,
-    substs: SubstsRef<'tcx>,
-) -> bool {
-    if ty_def.variants.len() != 2 {
-        return false;
-    }
+    /// Check if this enum can be safely exported based on the "nullable pointer optimization".
+    /// Currently restricted to function pointers, references, `core::num::NonZero*`,
+    /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
+    fn is_repr_nullable_ptr(
+        &self,
+        ty: Ty<'tcx>,
+        ty_def: &'tcx ty::AdtDef,
+        substs: SubstsRef<'tcx>,
+    ) -> bool {
+        if ty_def.variants.len() != 2 {
+            return false;
+        }
 
-    let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
-    let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
-    let fields = if variant_fields[0].is_empty() {
-        &variant_fields[1]
-    } else if variant_fields[1].is_empty() {
-        &variant_fields[0]
-    } else {
-        return false;
-    };
+        let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
+        let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
+        let fields = if variant_fields[0].is_empty() {
+            &variant_fields[1]
+        } else if variant_fields[1].is_empty() {
+            &variant_fields[0]
+        } else {
+            return false;
+        };
 
-    if fields.len() != 1 {
-        return false;
-    }
+        if fields.len() != 1 {
+            return false;
+        }
 
-    let field_ty = fields[0].ty(tcx, substs);
-    if !ty_is_known_nonnull(tcx, field_ty) {
-        return false;
-    }
+        let field_ty = fields[0].ty(self.cx.tcx, substs);
+        if !self.ty_is_known_nonnull(field_ty) {
+            return false;
+        }
 
-    // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
-    // If the computed size for the field and the enum are different, the nonnull optimization isn't
-    // being applied (and we've got a problem somewhere).
-    let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, ParamEnv::reveal_all()).unwrap();
-    if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
-        bug!("improper_ctypes: Option nonnull optimization not applied?");
-    }
+        // At this point, the field's type is known to be nonnull and the parent enum is
+        // Option-like. If the computed size for the field and the enum are different, the non-null
+        // optimization isn't being applied (and we've got a problem somewhere).
+        let compute_size_skeleton =
+            |t| SizeSkeleton::compute(t, self.cx.tcx, self.cx.param_env).unwrap();
+        if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
+            bug!("improper_ctypes: Option nonnull optimization not applied?");
+        }
 
-    true
-}
+        true
+    }
 
-impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the type is array and emit an unsafe type lint.
     fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         if let ty::Array(..) = ty.kind {
@@ -738,7 +742,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         // discriminant.
                         if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
                             // Special-case types like `Option<extern fn()>`.
-                            if !is_repr_nullable_ptr(cx, ty, def, substs) {
+                            if !self.is_repr_nullable_ptr(ty, def, substs) {
                                 return FfiUnsafe {
                                     ty,
                                     reason: "enum has no representation hint".into(),
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 25e57aa77acd0..2254d553337d5 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -1339,13 +1339,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 cdc8b5e90a642..d01c767e2bc04 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, UseSpecializedEncodable};
 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;
@@ -1004,18 +1004,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 0edea63f922d6..381e7ee115e17 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};
 
@@ -327,7 +327,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 3a4fc581f5f26..75c10de9bbe5e 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.
@@ -451,11 +458,11 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    pub fn visit_item_likes_in_module<V>(&self, module: DefId, visitor: &mut V)
+    pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
     where
         V: ItemLikeVisitor<'hir>,
     {
-        let module = self.tcx.hir_module_items(module.expect_local());
+        let module = self.tcx.hir_module_items(module);
 
         for id in &module.items {
             visitor.visit_item(self.expect_item(*id));
diff --git a/src/librustc_middle/hir/mod.rs b/src/librustc_middle/hir/mod.rs
index 1e3676496ce39..e152d11c081a1 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 27239b4ad2e78..bb62c1bb82428 100644
--- a/src/librustc_middle/lint.rs
+++ b/src/librustc_middle/lint.rs
@@ -339,7 +339,7 @@ pub fn struct_lint_level<'s, 'd>(
 pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     let expn_data = span.ctxt().outer_expn_data();
     match expn_data.kind {
-        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
+        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false,
         ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
         ExpnKind::Macro(MacroKind::Bang, _) => {
             // Dummy span for the `def_site` means it's an external macro.
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index 2f51b98085b4e..ba5a8c3ec2052 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -15,11 +15,11 @@ use rustc_query_system::query::QueryDescription;
 use rustc_span::symbol::Symbol;
 use std::borrow::Cow;
 
-fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     if def_id.is_top_level_module() {
         "top-level module".to_string()
     } else {
-        format!("module `{}`", tcx.def_path_str(def_id))
+        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
     }
 }
 
@@ -473,49 +473,49 @@ rustc_queries! {
 
     Other {
         query lint_mod(key: LocalDefId) -> () {
-            desc { |tcx| "linting {}", describe_as_module(key.to_def_id(), tcx) }
+            desc { |tcx| "linting {}", describe_as_module(key, tcx) }
         }
 
         /// Checks the attributes in the module.
-        query check_mod_attrs(key: DefId) -> () {
+        query check_mod_attrs(key: LocalDefId) -> () {
             desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_unstable_api_usage(key: DefId) -> () {
+        query check_mod_unstable_api_usage(key: LocalDefId) -> () {
             desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
         }
 
         /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`).
-        query check_mod_const_bodies(key: DefId) -> () {
+        query check_mod_const_bodies(key: LocalDefId) -> () {
             desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) }
         }
 
         /// Checks the loops in the module.
-        query check_mod_loops(key: DefId) -> () {
+        query check_mod_loops(key: LocalDefId) -> () {
             desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_item_types(key: DefId) -> () {
+        query check_mod_item_types(key: LocalDefId) -> () {
             desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
         }
 
         query check_mod_privacy(key: LocalDefId) -> () {
-            desc { |tcx| "checking privacy in {}", describe_as_module(key.to_def_id(), tcx) }
+            desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_intrinsics(key: DefId) -> () {
+        query check_mod_intrinsics(key: LocalDefId) -> () {
             desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_liveness(key: DefId) -> () {
+        query check_mod_liveness(key: LocalDefId) -> () {
             desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_impl_wf(key: DefId) -> () {
+        query check_mod_impl_wf(key: LocalDefId) -> () {
             desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
         }
 
-        query collect_mod_item_types(key: DefId) -> () {
+        query collect_mod_item_types(key: LocalDefId) -> () {
             desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
         }
 
@@ -729,7 +729,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_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index df08e083d2cbb..44c8c1f6fdba4 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -873,8 +873,8 @@ impl<'tcx> CommonConsts<'tcx> {
 // conflict.
 #[derive(Debug)]
 pub struct FreeRegionInfo {
-    // def id corresponding to FreeRegion
-    pub def_id: DefId,
+    // `LocalDefId` corresponding to FreeRegion
+    pub def_id: LocalDefId,
     // the bound region corresponding to FreeRegion
     pub boundregion: ty::BoundRegion,
     // checks if bound region is in Impl Item
@@ -1412,14 +1412,17 @@ impl<'tcx> TyCtxt<'tcx> {
     // Returns the `DefId` and the `BoundRegion` corresponding to the given region.
     pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
         let (suitable_region_binding_scope, bound_region) = match *region {
-            ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
-            ty::ReEarlyBound(ref ebr) => {
-                (self.parent(ebr.def_id).unwrap(), ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
+            ty::ReFree(ref free_region) => {
+                (free_region.scope.expect_local(), free_region.bound_region)
             }
+            ty::ReEarlyBound(ref ebr) => (
+                self.parent(ebr.def_id).unwrap().expect_local(),
+                ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
+            ),
             _ => return None, // not a free region
         };
 
-        let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope.expect_local());
+        let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope);
         let is_impl_item = match self.hir().find(hir_id) {
             Some(Node::Item(..) | Node::TraitItem(..)) => false,
             Some(Node::ImplItem(..)) => {
@@ -1436,8 +1439,11 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type.
-    pub fn return_type_impl_or_dyn_traits(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> {
-        let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
+    pub fn return_type_impl_or_dyn_traits(
+        &self,
+        scope_def_id: LocalDefId,
+    ) -> Vec<&'tcx hir::Ty<'tcx>> {
+        let hir_id = self.hir().as_local_hir_id(scope_def_id);
         let hir_output = match self.hir().get(hir_id) {
             Node::Item(hir::Item {
                 kind:
@@ -1480,9 +1486,9 @@ impl<'tcx> TyCtxt<'tcx> {
         v.0
     }
 
-    pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> {
+    pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
         // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`.
-        let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
+        let hir_id = self.hir().as_local_hir_id(scope_def_id);
         match self.hir().get(hir_id) {
             Node::Item(item) => {
                 match item.kind {
@@ -1512,8 +1518,9 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     // Checks if the bound region is in Impl Item.
-    pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool {
-        let container_id = self.associated_item(suitable_region_binding_scope).container.id();
+    pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool {
+        let container_id =
+            self.associated_item(suitable_region_binding_scope.to_def_id()).container.id();
         if self.impl_trait_ref(container_id).is_some() {
             // For now, we do not try to target impls of traits. This is
             // because this message is going to suggest that the user
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 60a1fe0b19870..e85f69554d0c8 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -24,7 +24,8 @@ use crate::borrow_check::{
 };
 
 use super::{
-    explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+    explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
+    RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -150,11 +151,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         format!("value moved{} here, in previous iteration of loop", move_msg),
                     );
                 } else {
-                    err.span_label(move_span, format!("value moved{} here", move_msg));
-                    move_spans.var_span_label(
-                        &mut err,
-                        format!("variable moved due to use{}", move_spans.describe()),
-                    );
+                    if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
+                        move_spans
+                    {
+                        let place_name = self
+                            .describe_place(moved_place.as_ref())
+                            .map(|n| format!("`{}`", n))
+                            .unwrap_or_else(|| "value".to_owned());
+                        match kind {
+                            FnSelfUseKind::FnOnceCall => {
+                                err.span_label(
+                                    fn_call_span,
+                                    &format!("{} moved due to this call", place_name),
+                                );
+                                err.span_note(
+                                    var_span,
+                                    "this value implements `FnOnce`, which causes it to be moved when called",
+                                );
+                            }
+                            FnSelfUseKind::Operator { self_arg } => {
+                                err.span_label(
+                                    fn_call_span,
+                                    &format!("{} moved due to usage in operator", place_name),
+                                );
+                                if self.fn_self_span_reported.insert(fn_span) {
+                                    err.span_note(
+                                        self_arg.span,
+                                        "calling this operator moves the left-hand side",
+                                    );
+                                }
+                            }
+                            FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
+                                if implicit_into_iter {
+                                    err.span_label(
+                                        fn_call_span,
+                                        &format!(
+                                            "{} moved due to this implicit call to `.into_iter()`",
+                                            place_name
+                                        ),
+                                    );
+                                } else {
+                                    err.span_label(
+                                        fn_call_span,
+                                        &format!("{} moved due to this method call", place_name),
+                                    );
+                                }
+                                // Avoid pointing to the same function in multiple different
+                                // error messages
+                                if self.fn_self_span_reported.insert(self_arg.span) {
+                                    err.span_note(
+                                        self_arg.span,
+                                        &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
+                                    );
+                                }
+                            }
+                        }
+                    } else {
+                        err.span_label(move_span, format!("value moved{} here", move_msg));
+                        move_spans.var_span_label(
+                            &mut err,
+                            format!("variable moved due to use{}", move_spans.describe()),
+                        );
+                    }
                 }
                 if let UseSpans::PatUse(span) = move_spans {
                     err.span_suggestion_verbose(
@@ -170,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     );
                 }
 
-                if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
+                if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
                     let sess = self.infcx.tcx.sess;
                     if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
                         err.span_suggestion(
diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 849fd63998db4..b591b938b5ac3 100644
--- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -509,7 +509,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // Used in a closure.
                 (LaterUseKind::ClosureCapture, var_span)
             }
-            UseSpans::PatUse(span) | UseSpans::OtherUse(span) => {
+            UseSpans::PatUse(span)
+            | UseSpans::OtherUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. } => {
                 let block = &self.body.basic_blocks()[location.block];
 
                 let kind = if let Some(&Statement {
diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
index 388076a9d60af..e94952e1c543c 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -4,6 +4,7 @@ use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
 use rustc_hir::GeneratorKind;
 use rustc_middle::mir::{
     AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
@@ -11,7 +12,11 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
-use rustc_span::{symbol::sym, Span};
+use rustc_span::{
+    hygiene::{DesugaringKind, ForLoopLoc},
+    symbol::sym,
+    Span,
+};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
@@ -33,6 +38,7 @@ crate use mutability_errors::AccessKind;
 crate use outlives_suggestion::OutlivesSuggestionBuilder;
 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
 crate use region_name::{RegionName, RegionNameSource};
+use rustc_span::symbol::Ident;
 
 pub(super) struct IncludingDowncast(pub(super) bool);
 
@@ -529,18 +535,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 }
 
-// The span(s) associated to a use of a place.
+/// The span(s) associated to a use of a place.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub(super) enum UseSpans {
-    // The access is caused by capturing a variable for a closure.
+    /// The access is caused by capturing a variable for a closure.
     ClosureUse {
-        // This is true if the captured variable was from a generator.
+        /// This is true if the captured variable was from a generator.
         generator_kind: Option<GeneratorKind>,
-        // The span of the args of the closure, including the `move` keyword if
-        // it's present.
+        /// The span of the args of the closure, including the `move` keyword if
+        /// it's present.
         args_span: Span,
-        // The span of the first use of the captured variable inside the closure.
+        /// The span of the first use of the captured variable inside the closure.
+        var_span: Span,
+    },
+    /// The access is caused by using a variable as the receiver of a method
+    /// that takes 'self'
+    FnSelfUse {
+        /// The span of the variable being moved
         var_span: Span,
+        /// The span of the method call on the variable
+        fn_call_span: Span,
+        /// The definition span of the method being called
+        fn_span: Span,
+        kind: FnSelfUseKind,
     },
     /// This access is caused by a `match` or `if let` pattern.
     PatUse(Span),
@@ -548,11 +565,22 @@ pub(super) enum UseSpans {
     OtherUse(Span),
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub(super) enum FnSelfUseKind {
+    /// A normal method call of the form `receiver.foo(a, b, c)`
+    Normal { self_arg: Ident, implicit_into_iter: bool },
+    /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
+    FnOnceCall,
+    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
+    Operator { self_arg: Ident },
+}
+
 impl UseSpans {
     pub(super) fn args_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { args_span: span, .. }
             | UseSpans::PatUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
         }
     }
@@ -561,6 +589,7 @@ impl UseSpans {
         match self {
             UseSpans::ClosureUse { var_span: span, .. }
             | UseSpans::PatUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
         }
     }
@@ -631,6 +660,7 @@ impl UseSpans {
         match self {
             closure @ UseSpans::ClosureUse { .. } => closure,
             UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
+            fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
         }
     }
 }
@@ -733,25 +763,112 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
         if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
-            let def_id = match kind {
+            match kind {
                 box AggregateKind::Closure(def_id, _)
-                | box AggregateKind::Generator(def_id, _, _) => def_id,
-                _ => return OtherUse(stmt.source_info.span),
+                | box AggregateKind::Generator(def_id, _, _) => {
+                    debug!("move_spans: def_id={:?} places={:?}", def_id, places);
+                    if let Some((args_span, generator_kind, var_span)) =
+                        self.closure_span(*def_id, moved_place, places)
+                    {
+                        return ClosureUse { generator_kind, args_span, var_span };
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        let normal_ret =
+            if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
+                PatUse(stmt.source_info.span)
+            } else {
+                OtherUse(stmt.source_info.span)
             };
 
-            debug!("move_spans: def_id={:?} places={:?}", def_id, places);
-            if let Some((args_span, generator_kind, var_span)) =
-                self.closure_span(*def_id, moved_place, places)
-            {
-                return ClosureUse { generator_kind, args_span, var_span };
+        // We are trying to find MIR of the form:
+        // ```
+        // _temp = _moved_val;
+        // ...
+        // FnSelfCall(_temp, ...)
+        // ```
+        //
+        // where `_moved_val` is the place we generated the move error for,
+        // `_temp` is some other local, and `FnSelfCall` is a function
+        // that has a `self` parameter.
+
+        let target_temp = match stmt.kind {
+            StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
+                temp.as_local().unwrap()
             }
-        }
+            _ => return normal_ret,
+        };
 
-        if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
-            PatUse(stmt.source_info.span)
-        } else {
-            OtherUse(stmt.source_info.span)
+        debug!("move_spans: target_temp = {:?}", target_temp);
+
+        if let Some(Terminator {
+            kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. },
+            ..
+        }) = &self.body[location.block].terminator
+        {
+            let mut method_did = None;
+            if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
+                if let ty::FnDef(def_id, _) = ty.kind {
+                    debug!("move_spans: fn = {:?}", def_id);
+                    if let Some(ty::AssocItem { fn_has_self_parameter, .. }) =
+                        self.infcx.tcx.opt_associated_item(def_id)
+                    {
+                        if *fn_has_self_parameter {
+                            method_did = Some(def_id);
+                        }
+                    }
+                }
+            }
+
+            let tcx = self.infcx.tcx;
+            let method_did = if let Some(did) = method_did { did } else { return normal_ret };
+
+            if let [Operand::Move(self_place), ..] = **args {
+                if self_place.as_local() == Some(target_temp) {
+                    let parent = tcx.parent(method_did);
+                    let is_fn_once = parent == tcx.lang_items().fn_once_trait();
+                    let is_operator = !from_hir_call
+                        && parent.map_or(false, |p| {
+                            tcx.lang_items().group(LangItemGroup::Op).contains(&p)
+                        });
+                    let fn_call_span = *fn_span;
+
+                    let self_arg = tcx.fn_arg_names(method_did)[0];
+
+                    let kind = if is_fn_once {
+                        FnSelfUseKind::FnOnceCall
+                    } else if is_operator {
+                        FnSelfUseKind::Operator { self_arg }
+                    } else {
+                        debug!(
+                            "move_spans: method_did={:?}, fn_call_span={:?}",
+                            method_did, fn_call_span
+                        );
+                        let implicit_into_iter = matches!(
+                            fn_call_span.desugaring_kind(),
+                            Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
+                        );
+                        FnSelfUseKind::Normal { self_arg, implicit_into_iter }
+                    };
+
+                    return FnSelfUse {
+                        var_span: stmt.source_info.span,
+                        fn_call_span,
+                        fn_span: self
+                            .infcx
+                            .tcx
+                            .sess
+                            .source_map()
+                            .guess_head_span(self.infcx.tcx.def_span(method_did)),
+                        kind,
+                    };
+                }
+            }
         }
+        return normal_ret;
     }
 
     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index b49e4187fb810..4883b08e42442 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 4d4b6fb9386db..b4bc89e827daa 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 f1923b9e81c66..99b9788c20b05 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -579,7 +579,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         if let (Some(f), Some(ty::RegionKind::ReStatic)) =
             (self.to_error_region(fr), self.to_error_region(outlived_fr))
         {
-            if let Some((ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self
+            if let Some((&ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self
                 .infcx
                 .tcx
                 .is_suitable_region(f)
@@ -592,7 +592,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 //
                 // eg. check for `impl Trait + 'static` instead of `impl Trait`.
                 let has_static_predicate = {
-                    let predicates_of = self.infcx.tcx.predicates_of(*did);
+                    let predicates_of = self.infcx.tcx.predicates_of(did);
                     let bounds = predicates_of.instantiate(self.infcx.tcx, substs);
 
                     let mut found = false;
@@ -625,7 +625,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str));
                 } else {
                     // Otherwise, we should suggest adding a constraint on the return type.
-                    let span = self.infcx.tcx.def_span(*did);
+                    let span = self.infcx.tcx.def_span(did);
                     if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
                         let suggestable_fr_name = if fr_name.was_named() {
                             fr_name.to_string()
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 03b663eb75056..83691d439eb81 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -278,6 +278,7 @@ fn do_mir_borrowck<'a, 'tcx>(
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
+                fn_self_span_reported: Default::default(),
                 locals_are_invalidated_at_exit,
                 access_place_error_reported: Default::default(),
                 reservation_error_reported: Default::default(),
@@ -311,6 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         location_table,
         movable_generator,
         locals_are_invalidated_at_exit,
+        fn_self_span_reported: Default::default(),
         access_place_error_reported: Default::default(),
         reservation_error_reported: Default::default(),
         reservation_warnings: Default::default(),
@@ -487,6 +489,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
     // but it is currently inconvenient to track down the `BorrowIndex`
     // at the time we detect and report a reservation error.
     reservation_error_reported: FxHashSet<Place<'tcx>>,
+    /// This fields keeps track of the `Span`s that we have
+    /// used to report extra information for `FnSelfUse`, to avoid
+    /// unnecessarily verbose errors.
+    fn_self_span_reported: FxHashSet<Span>,
     /// Migration warnings to be reported for #56254. We delay reporting these
     /// so that we can suppress the warning if there's a corresponding error
     /// for the activation of the borrow.
diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
index 3003f4639d9fa..7b292ee71f99d 100644
--- a/src/librustc_mir/borrow_check/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -232,8 +232,7 @@ impl<'tcx> UniversalRegions<'tcx> {
     ) -> Self {
         let tcx = infcx.tcx;
         let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
-        UniversalRegionsBuilder { infcx, mir_def_id: mir_def_id.to_def_id(), mir_hir_id, param_env }
-            .build()
+        UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build()
     }
 
     /// Given a reference to a closure type, extracts all the values
@@ -389,7 +388,7 @@ impl<'tcx> UniversalRegions<'tcx> {
 
 struct UniversalRegionsBuilder<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     mir_hir_id: HirId,
     param_env: ty::ParamEnv<'tcx>,
 }
@@ -418,7 +417,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id());
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -426,7 +425,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def_id != closure_base_def_id {
+        if self.mir_def_id.to_def_id() != closure_base_def_id {
             self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
         }
 
@@ -443,7 +442,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def_id == closure_base_def_id {
+        if self.mir_def_id.to_def_id() == closure_base_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
         }
@@ -508,14 +507,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def_id == closure_base_def_id {
+                let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id {
                     tcx.type_of(closure_base_def_id)
                 } else {
-                    let tables = tcx.typeck_tables_of(self.mir_def_id.expect_local());
+                    let tables = tcx.typeck_tables_of(self.mir_def_id);
                     tables.node_type(self.mir_hir_id)
                 };
 
@@ -540,11 +539,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(closure_base_def_id, self.mir_def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id);
                 let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                 let substs =
                     self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
-                DefiningTy::Const(self.mir_def_id, substs)
+                DefiningTy::Const(self.mir_def_id.to_def_id(), substs)
             }
         }
     }
@@ -559,7 +558,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
         let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
@@ -593,7 +592,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
         match defining_ty {
             DefiningTy::Closure(def_id, substs) => {
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), def_id);
                 let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
                 let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
@@ -617,7 +616,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             }
 
             DefiningTy::Generator(def_id, substs, movability) => {
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), def_id);
                 let resume_ty = substs.as_generator().resume_ty();
                 let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
@@ -635,7 +634,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             DefiningTy::Const(def_id, _) => {
                 // For a constant body, there are no inputs, and one
                 // "output" (the type of the constant).
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), def_id);
                 let ty = tcx.type_of(def_id);
                 let ty = indices.fold_to_region_vids(tcx, &ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
@@ -656,7 +655,7 @@ trait InferCtxtExt<'tcx> {
     fn replace_bound_regions_with_nll_infer_vars<T>(
         &self,
         origin: NLLRegionVariableOrigin,
-        all_outlive_scope: DefId,
+        all_outlive_scope: LocalDefId,
         value: &ty::Binder<T>,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) -> T
@@ -665,7 +664,7 @@ trait InferCtxtExt<'tcx> {
 
     fn replace_late_bound_regions_with_nll_infer_vars(
         &self,
-        mir_def_id: DefId,
+        mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
     );
 }
@@ -685,7 +684,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     fn replace_bound_regions_with_nll_infer_vars<T>(
         &self,
         origin: NLLRegionVariableOrigin,
-        all_outlive_scope: DefId,
+        all_outlive_scope: LocalDefId,
         value: &ty::Binder<T>,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) -> T
@@ -699,7 +698,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
             debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
             let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: all_outlive_scope,
+                scope: all_outlive_scope.to_def_id(),
                 bound_region: br,
             }));
             let region_vid = self.next_nll_region_var(origin);
@@ -724,11 +723,11 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     /// inputs vector.
     fn replace_late_bound_regions_with_nll_infer_vars(
         &self,
-        mir_def_id: DefId,
+        mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
         debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
-        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
+        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
         for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
             debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
             if !indices.indices.contains_key(&r) {
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 95e193b625354..9c72a18c6d469 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{
 };
 use rustc_middle::ty::layout::{self, TyAndLayout};
 use rustc_middle::ty::{
-    self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable,
+    self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::{source_map::DUMMY_SP, Span};
 use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
@@ -24,6 +24,7 @@ use super::{
     Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
     ScalarMaybeUninit, StackPopJump,
 };
+use crate::transform::validate::equal_up_to_regions;
 use crate::util::storage::AlwaysLiveLocals;
 
 pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
@@ -220,42 +221,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx,
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
     tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     src: TyAndLayout<'tcx>,
     dest: TyAndLayout<'tcx>,
 ) -> bool {
-    if src.ty == dest.ty {
-        // Equal types, all is good.
-        return true;
-    }
-    if src.layout != dest.layout {
-        // Layout differs, definitely not equal.
-        // We do this here because Miri would *do the wrong thing* if we allowed layout-changing
-        // assignments.
-        return false;
-    }
-
-    // Type-changing assignments can happen for (at least) two reasons:
-    // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
-    // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
-    //    with their late-bound lifetimes are still around and can lead to type differences.
-    // Normalize both of them away.
-    let normalize = |ty: Ty<'tcx>| {
-        ty.fold_with(&mut BottomUpFolder {
-            tcx,
-            // Normalize all references to immutable.
-            ty_op: |ty| match ty.kind {
-                ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee),
-                _ => ty,
-            },
-            // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
-            // lifetimes in invariant positions could matter (e.g. through associated types).
-            // We rely on the fact that layout was confirmed to be equal above.
-            lt_op: |_| tcx.lifetimes.re_erased,
-            // Leave consts unchanged.
-            ct_op: |ct| ct,
-        })
-    };
-    normalize(src.ty) == normalize(dest.ty)
+    // Type-changing assignments can happen when subtyping is used. While
+    // all normal lifetimes are erased, higher-ranked types with their
+    // late-bound lifetimes are still around and can lead to type
+    // differences. So we compare ignoring lifetimes.
+    if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) {
+        // Make sure the layout is equal, too -- just to be safe. Miri really
+        // needs layout equality. For performance reason we skip this check when
+        // the types are equal. Equal types *can* have different layouts when
+        // enum downcast is involved (as enum variants carry the type of the
+        // enum), but those should never occur in assignments.
+        if cfg!(debug_assertions) || src.ty != dest.ty {
+            assert_eq!(src.layout, dest.layout);
+        }
+        true
+    } else {
+        false
+    }
 }
 
 /// Use the already known layout if given (but sanity check in debug mode),
@@ -263,6 +249,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
 #[cfg_attr(not(debug_assertions), inline(always))]
 pub(super) fn from_known_layout<'tcx>(
     tcx: TyCtxtAt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     known_layout: Option<TyAndLayout<'tcx>>,
     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -271,7 +258,7 @@ pub(super) fn from_known_layout<'tcx>(
         Some(known_layout) => {
             if cfg!(debug_assertions) {
                 let check_layout = compute()?;
-                if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) {
+                if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
                     span_bug!(
                         tcx.span,
                         "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
@@ -475,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // have to support that case (mostly by skipping all caching).
         match frame.locals.get(local).and_then(|state| state.layout.get()) {
             None => {
-                let layout = from_known_layout(self.tcx, layout, || {
+                let layout = from_known_layout(self.tcx, self.param_env, layout, || {
                     let local_ty = frame.body.local_decls[local].ty;
                     let local_ty =
                         self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index dd746f5cfb409..fd55deaf83bba 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -488,6 +488,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Sanity-check the type we ended up with.
         debug_assert!(mir_assign_valid_types(
             *self.tcx,
+            self.param_env,
             self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
                 place.ty(&self.frame().body.local_decls, *self.tcx).ty
             ))?,
@@ -570,7 +571,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // documentation).
         let val_val = M::adjust_global_const(self, val_val)?;
         // Other cases need layout.
-        let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?;
+        let layout =
+            from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(val.ty))?;
         let op = match val_val {
             ConstValue::ByRef { alloc, offset } => {
                 let id = self.tcx.create_memory_alloc(alloc);
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 396aec0a8f89f..98a1cea97e220 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -652,6 +652,7 @@ where
         // Sanity-check the type we ended up with.
         debug_assert!(mir_assign_valid_types(
             *self.tcx,
+            self.param_env,
             self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
                 place.ty(&self.frame().body.local_decls, *self.tcx).ty
             ))?,
@@ -855,7 +856,7 @@ where
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        if !mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
+        if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
             span_bug!(
                 self.cur_span(),
                 "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
@@ -912,7 +913,7 @@ where
         src: OpTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
-        if mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
+        if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
             // Fast path: Just use normal `copy_op`
             return self.copy_op(src, dest);
         }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index e1c5a4f5b1885..a891f12c8e15f 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -512,6 +512,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/validate.rs b/src/librustc_mir/transform/validate.rs
index c5343d9b5d014..d3f486c815e6c 100644
--- a/src/librustc_mir/transform/validate.rs
+++ b/src/librustc_mir/transform/validate.rs
@@ -7,7 +7,11 @@ use rustc_middle::{
         BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
         TerminatorKind,
     },
-    ty::{self, ParamEnv, TyCtxt},
+    ty::{
+        self,
+        relate::{Relate, RelateResult, TypeRelation},
+        ParamEnv, Ty, TyCtxt,
+    },
 };
 
 #[derive(Copy, Clone, Debug)]
@@ -28,6 +32,98 @@ impl<'tcx> MirPass<'tcx> for Validator {
     }
 }
 
+/// Returns whether the two types are equal up to lifetimes.
+/// All lifetimes, including higher-ranked ones, get ignored for this comparison.
+/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.)
+///
+/// The point of this function is to approximate "equal up to subtyping".  However,
+/// the approximation is incorrect as variance is ignored.
+pub fn equal_up_to_regions(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    src: Ty<'tcx>,
+    dest: Ty<'tcx>,
+) -> bool {
+    // Fast path.
+    if src == dest {
+        return true;
+    }
+
+    struct LifetimeIgnoreRelation<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    }
+
+    impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> {
+        fn tcx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn param_env(&self) -> ty::ParamEnv<'tcx> {
+            self.param_env
+        }
+
+        fn tag(&self) -> &'static str {
+            "librustc_mir::transform::validate"
+        }
+
+        fn a_is_expected(&self) -> bool {
+            true
+        }
+
+        fn relate_with_variance<T: Relate<'tcx>>(
+            &mut self,
+            _: ty::Variance,
+            a: &T,
+            b: &T,
+        ) -> RelateResult<'tcx, T> {
+            // Ignore variance, require types to be exactly the same.
+            self.relate(a, b)
+        }
+
+        fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+            if a == b {
+                // Short-circuit.
+                return Ok(a);
+            }
+            ty::relate::super_relate_tys(self, a, b)
+        }
+
+        fn regions(
+            &mut self,
+            a: ty::Region<'tcx>,
+            _b: ty::Region<'tcx>,
+        ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+            // Ignore regions.
+            Ok(a)
+        }
+
+        fn consts(
+            &mut self,
+            a: &'tcx ty::Const<'tcx>,
+            b: &'tcx ty::Const<'tcx>,
+        ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+            ty::relate::super_relate_consts(self, a, b)
+        }
+
+        fn binders<T>(
+            &mut self,
+            a: &ty::Binder<T>,
+            b: &ty::Binder<T>,
+        ) -> RelateResult<'tcx, ty::Binder<T>>
+        where
+            T: Relate<'tcx>,
+        {
+            self.relate(a.skip_binder(), b.skip_binder())?;
+            Ok(a.clone())
+        }
+    }
+
+    // Instantiate and run relation.
+    let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
+    relator.relate(&src, &dest).is_ok()
+}
+
 struct TypeChecker<'a, 'tcx> {
     when: &'a str,
     source: MirSource<'tcx>,
@@ -81,6 +177,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
         }
     }
+
+    /// Check if src can be assigned into dest.
+    /// This is not precise, it will accept some incorrect assignments.
+    fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
+        // Fast path before we normalize.
+        if src == dest {
+            // Equal types, all is good.
+            return true;
+        }
+        // Normalize projections and things like that.
+        // FIXME: We need to reveal_all, as some optimizations change types in ways
+        // that require unfolding opaque types.
+        let param_env = self.param_env.with_reveal_all();
+        let src = self.tcx.normalize_erasing_regions(param_env, src);
+        let dest = self.tcx.normalize_erasing_regions(param_env, dest);
+
+        // Type-changing assignments can happen when subtyping is used. While
+        // all normal lifetimes are erased, higher-ranked types with their
+        // late-bound lifetimes are still around and can lead to type
+        // differences. So we compare ignoring lifetimes.
+        equal_up_to_regions(self.tcx, param_env, src, dest)
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
@@ -99,20 +217,37 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
     }
 
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        // The sides of an assignment must not alias. Currently this just checks whether the places
-        // are identical.
-        if let StatementKind::Assign(box (dest, rvalue)) = &statement.kind {
-            match rvalue {
-                Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
-                    if dest == src {
-                        self.fail(
-                            location,
-                            "encountered `Assign` statement with overlapping memory",
-                        );
+        match &statement.kind {
+            StatementKind::Assign(box (dest, rvalue)) => {
+                // LHS and RHS of the assignment must have the same type.
+                let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
+                let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
+                if !self.mir_assign_valid_types(right_ty, left_ty) {
+                    self.fail(
+                        location,
+                        format!(
+                            "encountered `Assign` statement with incompatible types:\n\
+                            left-hand side has type: {}\n\
+                            right-hand side has type: {}",
+                            left_ty, right_ty,
+                        ),
+                    );
+                }
+                // The sides of an assignment must not alias. Currently this just checks whether the places
+                // are identical.
+                match rvalue {
+                    Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
+                        if dest == src {
+                            self.fail(
+                                location,
+                                "encountered `Assign` statement with overlapping memory",
+                            );
+                        }
                     }
+                    _ => {}
                 }
-                _ => {}
             }
+            _ => {}
         }
     }
 
diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs
index 408f2e8c19a5d..ef84f251390e6 100644
--- a/src/librustc_passes/check_attr.rs
+++ b/src/librustc_passes/check_attr.rs
@@ -12,7 +12,7 @@ use rustc_ast::ast::{Attribute, NestedMetaItem};
 use rustc_ast::attr;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{self, HirId, Item, ItemKind, TraitItem};
 use rustc_hir::{MethodKind, Target};
@@ -464,7 +464,7 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
     }
 }
 
-fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir()
         .visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
 }
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index 94f9c619a3a26..90a076eeded7e 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -9,7 +9,7 @@
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
@@ -62,7 +62,7 @@ impl NonConstExpr {
     }
 }
 
-fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let mut vis = CheckConstVisitor::new(tcx);
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
 }
diff --git a/src/librustc_passes/hir_id_validator.rs b/src/librustc_passes/hir_id_validator.rs
index 80dfcd9c2417a..2edbc29b7efb6 100644
--- a/src/librustc_passes/hir_id_validator.rs
+++ b/src/librustc_passes/hir_id_validator.rs
@@ -17,7 +17,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
         let local_def_id = hir_map.local_def_id(*module_id);
         hir_map.visit_item_likes_in_module(
-            local_def_id.to_def_id(),
+            local_def_id,
             &mut OuterVisitor { hir_map, errors: &errors },
         );
     });
diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs
index c8666ba1fd078..683039df15ac6 100644
--- a/src/librustc_passes/intrinsicck.rs
+++ b/src/librustc_passes/intrinsicck.rs
@@ -2,7 +2,7 @@ use rustc_ast::ast::{FloatTy, InlineAsmTemplatePiece, IntTy, UintTy};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
@@ -14,7 +14,7 @@ use rustc_target::abi::{Pointer, VariantIdx};
 use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 
-fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
 }
 
diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs
index f4167c8644e6e..0be37cb096038 100644
--- a/src/librustc_passes/lang_items.rs
+++ b/src/librustc_passes/lang_items.rs
@@ -102,7 +102,8 @@ impl LanguageItemCollector<'tcx> {
         // Check for duplicates.
         if let Some(original_def_id) = self.items.items[item_index] {
             if original_def_id != item_def_id {
-                let name = LangItem::from_u32(item_index as u32).unwrap().name();
+                let lang_item = LangItem::from_u32(item_index as u32).unwrap();
+                let name = lang_item.name();
                 let mut err = match self.tcx.hir().span_if_local(item_def_id) {
                     Some(span) => struct_span_err!(
                         self.tcx.sess,
@@ -152,6 +153,9 @@ impl LanguageItemCollector<'tcx> {
 
         // Matched.
         self.items.items[item_index] = Some(item_def_id);
+        if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
+            self.items.groups[group as usize].push(item_def_id);
+        }
     }
 }
 
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index ff5dabd5418c9..798c6b8925bbf 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -89,7 +89,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::*;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node};
 use rustc_middle::hir::map::Map;
@@ -172,7 +172,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
     }
 }
 
-fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
@@ -248,7 +248,7 @@ enum VarKind {
 
 struct IrMaps<'tcx> {
     tcx: TyCtxt<'tcx>,
-    body_owner: DefId,
+    body_owner: LocalDefId,
     num_live_nodes: usize,
     num_vars: usize,
     live_node_map: HirIdMap<LiveNode>,
@@ -259,7 +259,7 @@ struct IrMaps<'tcx> {
 }
 
 impl IrMaps<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, body_owner: DefId) -> IrMaps<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> {
         IrMaps {
             tcx,
             body_owner,
@@ -349,7 +349,7 @@ fn visit_fn<'tcx>(
 
     // swap in a new set of IR maps for this function body:
     let def_id = ir.tcx.hir().local_def_id(id);
-    let mut fn_maps = IrMaps::new(ir.tcx, def_id.to_def_id());
+    let mut fn_maps = IrMaps::new(ir.tcx, def_id);
 
     // Don't run unused pass for #[derive()]
     if let FnKind::Method(..) = fk {
@@ -484,7 +484,7 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
             }
             ir.set_captures(expr.hir_id, call_caps);
             let old_body_owner = ir.body_owner;
-            ir.body_owner = closure_def_id.to_def_id();
+            ir.body_owner = closure_def_id;
             intravisit::walk_expr(ir, expr);
             ir.body_owner = old_body_owner;
         }
@@ -937,7 +937,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             for (&var_hir_id, upvar) in upvars.iter().rev() {
                 let upvar_id = ty::UpvarId {
                     var_path: ty::UpvarPath { hir_id: var_hir_id },
-                    closure_expr_id: self.ir.body_owner.expect_local(),
+                    closure_expr_id: self.ir.body_owner,
                 };
                 match self.tables.upvar_capture(upvar_id) {
                     ty::UpvarCapture::ByRef(_) => {
@@ -1614,7 +1614,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
             let var = self.variable(var_hir_id, upvar.span);
             let upvar_id = ty::UpvarId {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
-                closure_expr_id: self.ir.body_owner.expect_local(),
+                closure_expr_id: self.ir.body_owner,
             };
             match self.tables.upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => {}
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 767a6909d31d4..d7012d4d711df 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -2,7 +2,7 @@ use Context::*;
 
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Destination, Movability, Node};
 use rustc_middle::hir::map::Map;
@@ -29,7 +29,7 @@ struct CheckLoopVisitor<'a, 'hir> {
     cx: Context,
 }
 
-fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index 054748c09fc44..ad512c63352f1 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Generics, HirId, Item, StructField, Variant};
 use rustc_middle::hir::map::Map;
@@ -472,7 +472,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
 
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
-fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
 }
 
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 2ea312c42dc64..fcd5dab94a6c2 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -1061,8 +1061,15 @@ fn default_emitter(
             }
         }
         (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
-            JsonEmitter::stderr(Some(registry), source_map, pretty, json_rendered, macro_backtrace)
-                .ui_testing(sopts.debugging_opts.ui_testing),
+            JsonEmitter::stderr(
+                Some(registry),
+                source_map,
+                pretty,
+                json_rendered,
+                sopts.debugging_opts.terminal_width,
+                macro_backtrace,
+            )
+            .ui_testing(sopts.debugging_opts.ui_testing),
         ),
         (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
             JsonEmitter::new(
@@ -1071,6 +1078,7 @@ fn default_emitter(
                 source_map,
                 pretty,
                 json_rendered,
+                sopts.debugging_opts.terminal_width,
                 macro_backtrace,
             )
             .ui_testing(sopts.debugging_opts.ui_testing),
@@ -1416,7 +1424,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
             Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
         }
         config::ErrorOutputType::Json { pretty, json_rendered } => {
-            Box::new(JsonEmitter::basic(pretty, json_rendered, false))
+            Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
         }
     };
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
@@ -1431,7 +1439,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
             Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
         }
         config::ErrorOutputType::Json { pretty, json_rendered } => {
-            Box::new(JsonEmitter::basic(pretty, json_rendered, false))
+            Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
         }
     };
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs
index c0fb84e741f4a..60bbdd0495cc4 100644
--- a/src/librustc_span/hygiene.rs
+++ b/src/librustc_span/hygiene.rs
@@ -822,7 +822,14 @@ pub enum DesugaringKind {
     OpaqueTy,
     Async,
     Await,
-    ForLoop,
+    ForLoop(ForLoopLoc),
+}
+
+/// A location in the desugaring of a `for` loop
+#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+pub enum ForLoopLoc {
+    Head,
+    IntoIter,
 }
 
 impl DesugaringKind {
@@ -835,7 +842,7 @@ impl DesugaringKind {
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
-            DesugaringKind::ForLoop => "`for` loop",
+            DesugaringKind::ForLoop(_) => "`for` loop",
         }
     }
 }
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index 9624006683467..dcd2e83b74713 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -30,8 +30,9 @@ use source_map::SourceMap;
 pub mod edition;
 use edition::Edition;
 pub mod hygiene;
+pub use hygiene::SyntaxContext;
 use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, MacroKind, SyntaxContext};
+pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
 pub mod def_id;
 use def_id::{CrateNum, DefId, LOCAL_CRATE};
 mod span_encoding;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0325782e69d51..7c4048ab22302 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -737,7 +737,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) {
     tcx.hir().krate().par_visit_all_item_likes(&visit);
 }
 
-fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
 }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 054165f2b0977..b486e3d3536c9 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -55,7 +55,7 @@ struct OnlySelfBounds(bool);
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
-fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 37d383db68ab6..77cd1b3de0106 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -14,7 +14,7 @@ use min_specialization::check_min_specialization;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
@@ -59,11 +59,11 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) {
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
     for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module).to_def_id());
+        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module));
     }
 }
 
-fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let min_specialization = tcx.features().min_specialization;
     tcx.hir()
         .visit_item_likes_in_module(module_def_id, &mut ImplWfCheck { tcx, min_specialization });
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 8ab6c74289d17..38f202e84accb 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -193,8 +193,15 @@ pub fn new_handler(
                 Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
             });
             Box::new(
-                JsonEmitter::stderr(None, source_map, pretty, json_rendered, false)
-                    .ui_testing(debugging_opts.ui_testing),
+                JsonEmitter::stderr(
+                    None,
+                    source_map,
+                    pretty,
+                    json_rendered,
+                    debugging_opts.terminal_width,
+                    false,
+                )
+                .ui_testing(debugging_opts.ui_testing),
             )
         }
     };
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index f4c164a324e32..17f890375f843 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1033,8 +1033,16 @@ impl Metadata {
     /// [`is_dir`], and will be false for symlink metadata
     /// obtained from [`symlink_metadata`].
     ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
     /// [`is_dir`]: struct.Metadata.html#method.is_dir
     /// [`symlink_metadata`]: fn.symlink_metadata.html
+    /// [`File::open`]: struct.File.html#method.open
+    /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
     ///
     /// # Examples
     ///
@@ -1307,8 +1315,16 @@ impl FileType {
     /// [`is_dir`] and [`is_symlink`]; only zero or one of these
     /// tests may pass.
     ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
     /// [`is_dir`]: struct.FileType.html#method.is_dir
     /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+    /// [`File::open`]: struct.File.html#method.open
+    /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
     ///
     /// # Examples
     ///
@@ -1429,7 +1445,10 @@ impl DirEntry {
     /// Returns the metadata for the file that this entry points at.
     ///
     /// This function will not traverse symlinks if this entry points at a
-    /// symlink.
+    /// symlink. To traverse symlinks use [`fs::metadata`] or [`fs::File::metadata`].
+    ///
+    /// [`fs::metadata`]: fn.metadata.html
+    /// [`fs::File::metadata`]: struct.File.html#method.metadata
     ///
     /// # Platform-specific behavior
     ///
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 8ff7508ba6457..f14a9ff72f62f 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -2503,11 +2503,20 @@ impl Path {
     /// # See Also
     ///
     /// This is a convenience function that coerces errors to false. If you want to
-    /// check errors, call [fs::metadata] and handle its Result. Then call
-    /// [fs::Metadata::is_file] if it was Ok.
-    ///
-    /// [fs::metadata]: ../../std/fs/fn.metadata.html
-    /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
+    /// check errors, call [`fs::metadata`] and handle its Result. Then call
+    /// [`fs::Metadata::is_file`] if it was Ok.
+    ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
+    /// [`fs::metadata`]: ../../std/fs/fn.metadata.html
+    /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html
+    /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file
+    /// [`File::open`]: ../../std/fs/struct.File.html#method.open
+    /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn is_file(&self) -> bool {
         fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 9bc111c26ba6b..41b14714842fd 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -49,8 +49,10 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
 
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+#if LLVM_VERSION_LT(11, 0)
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
                                    LLVMPassManagerBuilderRef)
+#endif
 
 extern "C" void LLVMInitializePasses() {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
@@ -343,17 +345,17 @@ enum class LLVMRustPassBuilderOptLevel {
 static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
   switch (Level) {
   case LLVMRustPassBuilderOptLevel::O0:
-    return PassBuilder::O0;
+    return PassBuilder::OptimizationLevel::O0;
   case LLVMRustPassBuilderOptLevel::O1:
-    return PassBuilder::O1;
+    return PassBuilder::OptimizationLevel::O1;
   case LLVMRustPassBuilderOptLevel::O2:
-    return PassBuilder::O2;
+    return PassBuilder::OptimizationLevel::O2;
   case LLVMRustPassBuilderOptLevel::O3:
-    return PassBuilder::O3;
+    return PassBuilder::OptimizationLevel::O3;
   case LLVMRustPassBuilderOptLevel::Os:
-    return PassBuilder::Os;
+    return PassBuilder::OptimizationLevel::Os;
   case LLVMRustPassBuilderOptLevel::Oz:
-    return PassBuilder::Oz;
+    return PassBuilder::OptimizationLevel::Oz;
   default:
     report_fatal_error("Bad PassBuilderOptLevel.");
   }
@@ -796,8 +798,13 @@ LLVMRustOptimizeWithNewPassManager(
   // We manually collect pipeline callbacks so we can apply them at O0, where the
   // PassBuilder does not create a pipeline.
   std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks;
+#if LLVM_VERSION_GE(11, 0)
+  std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>>
+      OptimizerLastEPCallbacks;
+#else
   std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>>
       OptimizerLastEPCallbacks;
+#endif
 
   if (VerifyIR) {
     PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) {
@@ -811,6 +818,14 @@ LLVMRustOptimizeWithNewPassManager(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
           SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false);
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(MemorySanitizerPass(Options));
+          MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
+        }
+      );
+#else
 #if LLVM_VERSION_GE(10, 0)
       PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) {
         MPM.addPass(MemorySanitizerPass(Options));
@@ -821,9 +836,18 @@ LLVMRustOptimizeWithNewPassManager(
           FPM.addPass(MemorySanitizerPass(Options));
         }
       );
+#endif
     }
 
     if (SanitizerOptions->SanitizeThread) {
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(ThreadSanitizerPass());
+          MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
+        }
+      );
+#else
 #if LLVM_VERSION_GE(10, 0)
       PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) {
         MPM.addPass(ThreadSanitizerPass());
@@ -834,9 +858,22 @@ LLVMRustOptimizeWithNewPassManager(
           FPM.addPass(ThreadSanitizerPass());
         }
       );
+#endif
     }
 
     if (SanitizerOptions->SanitizeAddress) {
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
+          MPM.addPass(ModuleAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
+          MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
+              /*UseAfterScope=*/true)));
+        }
+      );
+#else
       PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) {
         MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
       });
@@ -853,21 +890,27 @@ LLVMRustOptimizeWithNewPassManager(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
         }
       );
+#endif
     }
   }
 
   ModulePassManager MPM(DebugPassManager);
   if (!NoPrepopulatePasses) {
-    if (OptLevel == PassBuilder::O0) {
+    if (OptLevel == PassBuilder::OptimizationLevel::O0) {
       for (const auto &C : PipelineStartEPCallbacks)
         C(MPM);
 
+#if LLVM_VERSION_GE(11, 0)
+      for (const auto &C : OptimizerLastEPCallbacks)
+        C(MPM, OptLevel);
+#else
       if (!OptimizerLastEPCallbacks.empty()) {
         FunctionPassManager FPM(DebugPassManager);
         for (const auto &C : OptimizerLastEPCallbacks)
           C(FPM, OptLevel);
         MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
       }
+#endif
 
       MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
 
@@ -892,12 +935,17 @@ LLVMRustOptimizeWithNewPassManager(
         break;
       case LLVMRustOptStage::PreLinkThinLTO:
         MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
+#if LLVM_VERSION_GE(11, 0)
+        for (const auto &C : OptimizerLastEPCallbacks)
+          C(MPM, OptLevel);
+#else
         if (!OptimizerLastEPCallbacks.empty()) {
           FunctionPassManager FPM(DebugPassManager);
           for (const auto &C : OptimizerLastEPCallbacks)
             C(FPM, OptLevel);
           MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
         }
+#endif
         break;
       case LLVMRustOptStage::PreLinkFatLTO:
         MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
@@ -994,10 +1042,10 @@ class RustAssemblyAnnotationWriter : public AssemblyAnnotationWriter {
     const Value *Value;
     if (const CallInst *CI = dyn_cast<CallInst>(I)) {
       Name = "call";
-      Value = CI->getCalledValue();
+      Value = CI->getCalledOperand();
     } else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) {
       Name = "invoke";
-      Value = II->getCalledValue();
+      Value = II->getCalledOperand();
     } else {
       // Could demangle more operations, e. g.
       // `store %place, @function`.
@@ -1335,10 +1383,33 @@ LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
 // `ProcessThinLTOModule` function. Here they're split up into separate steps
 // so rustc can save off the intermediate bytecode between each step.
 
+#if LLVM_VERSION_GE(11, 0)
+static bool
+clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
+  // When linking an ELF shared object, dso_local should be dropped. We
+  // conservatively do this for -fpic.
+  bool ClearDSOLocalOnDeclarations =
+      TM.getTargetTriple().isOSBinFormatELF() &&
+      TM.getRelocationModel() != Reloc::Static &&
+      Mod.getPIELevel() == PIELevel::Default;
+  return ClearDSOLocalOnDeclarations;
+}
+#endif
+
 extern "C" bool
-LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
+                             LLVMTargetMachineRef TM) {
   Module &Mod = *unwrap(M);
-  if (renameModuleForThinLTO(Mod, Data->Index)) {
+  TargetMachine &Target = *unwrap(TM);
+
+#if LLVM_VERSION_GE(11, 0)
+  bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
+  bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
+#else
+  bool error = renameModuleForThinLTO(Mod, Data->Index);
+#endif
+
+  if (error) {
     LLVMRustSetLastError("renameModuleForThinLTO failed");
     return false;
   }
@@ -1362,8 +1433,10 @@ LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef
 }
 
 extern "C" bool
-LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
+                             LLVMTargetMachineRef TM) {
   Module &Mod = *unwrap(M);
+  TargetMachine &Target = *unwrap(TM);
 
   const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
   auto Loader = [&](StringRef Identifier) {
@@ -1399,7 +1472,12 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
 
     return MOrErr;
   };
+#if LLVM_VERSION_GE(11, 0)
+  bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
+  FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
+#else
   FunctionImporter Importer(Data->Index, Loader);
+#endif
   Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
   if (!Result) {
     LLVMRustSetLastError(toString(Result.takeError()).c_str());
@@ -1558,22 +1636,11 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
   }
 
   // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and
-  // process it recursively. Note that we specifically iterate over instructions
-  // to ensure we feed everything into it.
+  // process it recursively. Note that we used to specifically iterate over
+  // instructions to ensure we feed everything into it, but `processModule`
+  // started doing this the same way in LLVM 7 (commit d769eb36ab2b8).
   DebugInfoFinder Finder;
   Finder.processModule(*M);
-  for (Function &F : M->functions()) {
-    for (auto &FI : F) {
-      for (Instruction &BI : FI) {
-        if (auto Loc = BI.getDebugLoc())
-          Finder.processLocation(*M, Loc);
-        if (auto DVI = dyn_cast<DbgValueInst>(&BI))
-          Finder.processValue(*M, DVI);
-        if (auto DDI = dyn_cast<DbgDeclareInst>(&BI))
-          Finder.processDeclare(*M, DDI);
-      }
-    }
-  }
 
   // After we've found all our debuginfo, rewrite all subprograms to point to
   // the same `DICompileUnit`.
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index cdb3a157eab97..063b6acc604ea 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -1,5 +1,4 @@
 #include "rustllvm.h"
-#include "llvm/IR/CallSite.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
@@ -214,50 +213,50 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
 
 extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index,
                                              LLVMRustAttribute RustAttr) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr));
-  Call.addAttribute(Index, Attr);
+  Call->addAttribute(Index, Attr);
 }
 
 extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
                                                  unsigned Index,
                                                  uint32_t Bytes) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   AttrBuilder B;
   B.addAlignmentAttr(Bytes);
-  Call.setAttributes(Call.getAttributes().addAttributes(
+  Call->setAttributes(Call->getAttributes().addAttributes(
       Call->getContext(), Index, B));
 }
 
 extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
                                                        unsigned Index,
                                                        uint64_t Bytes) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   AttrBuilder B;
   B.addDereferenceableAttr(Bytes);
-  Call.setAttributes(Call.getAttributes().addAttributes(
+  Call->setAttributes(Call->getAttributes().addAttributes(
       Call->getContext(), Index, B));
 }
 
 extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
                                                              unsigned Index,
                                                              uint64_t Bytes) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   AttrBuilder B;
   B.addDereferenceableOrNullAttr(Bytes);
-  Call.setAttributes(Call.getAttributes().addAttributes(
+  Call->setAttributes(Call->getAttributes().addAttributes(
       Call->getContext(), Index, B));
 }
 
 extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
                                              LLVMTypeRef Ty) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
 #if LLVM_VERSION_GE(9, 0)
   Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty));
 #else
   Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal);
 #endif
-  Call.addAttribute(Index, Attr);
+  Call->addAttribute(Index, Attr);
 }
 
 extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
@@ -336,20 +335,24 @@ extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) {
 extern "C" LLVMValueRef
 LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef Source, const char *Name,
                         LLVMAtomicOrdering Order) {
-  LoadInst *LI = new LoadInst(unwrap(Source));
+  Value *Ptr = unwrap(Source);
+  Type *Ty = Ptr->getType()->getPointerElementType();
+  LoadInst *LI = unwrap(B)->CreateLoad(Ty, Ptr, Name);
   LI->setAtomic(fromRust(Order));
-  return wrap(unwrap(B)->Insert(LI, Name));
+  return wrap(LI);
 }
 
 extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B,
                                                  LLVMValueRef V,
                                                  LLVMValueRef Target,
                                                  LLVMAtomicOrdering Order) {
-  StoreInst *SI = new StoreInst(unwrap(V), unwrap(Target));
+  StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target));
   SI->setAtomic(fromRust(Order));
-  return wrap(unwrap(B)->Insert(SI));
+  return wrap(SI);
 }
 
+// FIXME: Use the C-API LLVMBuildAtomicCmpXchg and LLVMSetWeak
+// once we raise our minimum support to LLVM 10.
 extern "C" LLVMValueRef
 LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target,
                            LLVMValueRef Old, LLVMValueRef Source,
@@ -965,8 +968,14 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
     const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
+#if LLVM_VERSION_GE(11, 0)
+  bool IsDefault = false; // FIXME: should we ever set this true?
+  return wrap(Builder->createTemplateTypeParameter(
+      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
+#else
   return wrap(Builder->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
+#endif
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
@@ -1227,12 +1236,23 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMArrayTypeKind;
   case Type::PointerTyID:
     return LLVMPointerTypeKind;
+#if LLVM_VERSION_GE(11, 0)
+  case Type::FixedVectorTyID:
+    return LLVMVectorTypeKind;
+#else
   case Type::VectorTyID:
     return LLVMVectorTypeKind;
+#endif
   case Type::X86_MMXTyID:
     return LLVMX86_MMXTypeKind;
   case Type::TokenTyID:
     return LLVMTokenTypeKind;
+#if LLVM_VERSION_GE(11, 0)
+  case Type::ScalableVectorTyID:
+    return LLVMScalableVectorTypeKind;
+  case Type::BFloatTyID:
+    return LLVMBFloatTypeKind;
+#endif
   }
   report_fatal_error("Unhandled TypeID.");
 }
@@ -1359,10 +1379,12 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
 extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
                                           LLVMValueRef *Args, unsigned NumArgs,
                                           OperandBundleDef *Bundle) {
+  Value *Callee = unwrap(Fn);
+  FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
   unsigned Len = Bundle ? 1 : 0;
   ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
   return wrap(unwrap(B)->CreateCall(
-      unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles));
+      FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles));
 }
 
 extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) {
@@ -1422,9 +1444,11 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
                     unsigned NumArgs, LLVMBasicBlockRef Then,
                     LLVMBasicBlockRef Catch, OperandBundleDef *Bundle,
                     const char *Name) {
+  Value *Callee = unwrap(Fn);
+  FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
   unsigned Len = Bundle ? 1 : 0;
   ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
-  return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch),
+  return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
                                       makeArrayRef(unwrap(Args), NumArgs),
                                       Bundles, Name));
 }
diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs
index 719f219ce4ef1..433d32abd37c6 100644
--- a/src/test/codegen/sanitizer-recover.rs
+++ b/src/test/codegen/sanitizer-recover.rs
@@ -27,17 +27,17 @@
 // ASAN:               }
 //
 // MSAN-LABEL: define i32 @penguin(
-// MSAN:         call void @__msan_warning_noreturn()
+// MSAN:         call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}}
 // MSAN:         unreachable
 // MSAN:       }
 //
 // MSAN-RECOVER-LABEL: define i32 @penguin(
-// MSAN-RECOVER:         call void @__msan_warning()
+// MSAN-RECOVER:         call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
 // MSAN-RECOVER-NOT:     unreachable
 // MSAN-RECOVER:       }
 //
 // MSAN-RECOVER-LTO-LABEL: define i32 @penguin(
-// MSAN-RECOVER-LTO:          call void @__msan_warning()
+// MSAN-RECOVER-LTO:          call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
 // MSAN-RECOVER-LTO-NOT:      unreachable
 // MSAN-RECOVER-LTO:       }
 //
diff --git a/src/test/ui/async-await/async-error-span.rs b/src/test/ui/async-await/async-error-span.rs
index cf10ebfeca939..86d459bf084b1 100644
--- a/src/test/ui/async-await/async-error-span.rs
+++ b/src/test/ui/async-await/async-error-span.rs
@@ -5,7 +5,7 @@
 use std::future::Future;
 
 fn get_future() -> impl Future<Output = ()> {
-//~^ ERROR the trait bound `(): std::future::Future` is not satisfied
+//~^ ERROR `()` is not a future
     panic!()
 }
 
diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr
index 4054e739c483d..9523f040aa8cd 100644
--- a/src/test/ui/async-await/async-error-span.stderr
+++ b/src/test/ui/async-await/async-error-span.stderr
@@ -1,12 +1,13 @@
-error[E0277]: the trait bound `(): std::future::Future` is not satisfied
+error[E0277]: `()` is not a future
   --> $DIR/async-error-span.rs:7:20
    |
 LL | fn get_future() -> impl Future<Output = ()> {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
 LL |
 LL |     panic!()
    |     -------- this returned value is of type `!`
    |
+   = help: the trait `std::future::Future` is not implemented for `()`
    = note: the return type of a function must have a statically known size
 
 error[E0698]: type inside `async fn` body must be known in this context
diff --git a/src/test/ui/async-await/issue-70594.rs b/src/test/ui/async-await/issue-70594.rs
index e78231a68512d..34d12db8806dc 100644
--- a/src/test/ui/async-await/issue-70594.rs
+++ b/src/test/ui/async-await/issue-70594.rs
@@ -6,7 +6,7 @@ async fn fun() {
     //~| error: `.await` is not allowed in a `const`
     //~| error: `loop` is not allowed in a `const`
     //~| error: `.await` is not allowed in a `const`
-    //~| error: the trait bound `(): std::future::Future` is not satisfied
+    //~| error: `()` is not a future
 }
 
 fn main() {}
diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr
index 496ca506c60f2..1b7abe317222d 100644
--- a/src/test/ui/async-await/issue-70594.stderr
+++ b/src/test/ui/async-await/issue-70594.stderr
@@ -27,12 +27,13 @@ error[E0744]: `.await` is not allowed in a `const`
 LL |     [1; ().await];
    |         ^^^^^^^^
 
-error[E0277]: the trait bound `(): std::future::Future` is not satisfied
+error[E0277]: `()` is not a future
   --> $DIR/issue-70594.rs:4:9
    |
 LL |     [1; ().await];
-   |         ^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
+   |         ^^^^^^^^ `()` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `()`
    = note: required by `std::future::Future::poll`
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr
index ec4e9e397a81e..e3ba74a03c898 100644
--- a/src/test/ui/async-await/issues/issue-62009-1.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-1.stderr
@@ -27,12 +27,13 @@ LL | fn main() {
 LL |     (|_| 2333).await;
    |     ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
-error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]: std::future::Future` is not satisfied
+error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
   --> $DIR/issue-62009-1.rs:12:5
    |
 LL |     (|_| 2333).await;
-   |     ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+   |     ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
    = note: required by `std::future::Future::poll`
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/binop/binop-consume-args.stderr b/src/test/ui/binop/binop-consume-args.stderr
index acdc03e372638..addc8a0efe1aa 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 6d5ac9cab30c0..97b70efe20e79 100644
--- a/src/test/ui/binop/binop-move-semantics.stderr
+++ b/src/test/ui/binop/binop-move-semantics.stderr
@@ -1,14 +1,21 @@
 error[E0382]: use of moved value: `x`
   --> $DIR/binop-move-semantics.rs:8:5
    |
-LL | fn double_move<T: Add<Output=()>>(x: T) {
-   |                                   - move occurs because `x` has type `T`, which does not implement the `Copy` trait
-LL |     x
-   |     - value moved here
-LL |     +
-LL |     x;
-   |     ^ value used here after move
+LL |   fn double_move<T: Add<Output=()>>(x: T) {
+   |                                     - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+LL | /     x
+LL | |     +
+LL | |     x;
+   | |     ^
+   | |     |
+   | |_____value used here after move
+   |       `x` moved due to usage in operator
+   |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/arith.rs:LL:COL
    |
+LL |     fn add(self, rhs: Rhs) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn double_move<T: Add<Output=()> + Copy>(x: T) {
diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
index a51cda548efd7..bc1721944fbbb 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 69d98654048cb..896bb6dc6bee8 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 97816a76004d0..614e69e89f6ec 100644
--- a/src/test/ui/codemap_tests/tab_3.stderr
+++ b/src/test/ui/codemap_tests/tab_3.stderr
@@ -4,10 +4,16 @@ error[E0382]: borrow of moved value: `some_vec`
 LL |     let some_vec = vec!["hi"];
    |         -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
 LL |     some_vec.into_iter();
-   |     -------- value moved here
+   |              ----------- `some_vec` moved due to this method call
 LL |     {
 LL |         println!("{:?}", some_vec);
    |                          ^^^^^^^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues-71798.rs b/src/test/ui/issues-71798.rs
index 08b10463d3927..fecba721ac9fd 100644
--- a/src/test/ui/issues-71798.rs
+++ b/src/test/ui/issues-71798.rs
@@ -1,5 +1,5 @@
 fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
-    *x //~^ ERROR the trait bound `u32: std::future::Future` is not satisfied
+    *x //~^ ERROR `u32` is not a future
 }
 
 fn main() {
diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr
index 85da87914e768..b3b29a7264131 100644
--- a/src/test/ui/issues-71798.stderr
+++ b/src/test/ui/issues-71798.stderr
@@ -4,14 +4,15 @@ error[E0425]: cannot find value `u` in this scope
 LL |     let _ = test_ref & u;
    |                        ^ not found in this scope
 
-error[E0277]: the trait bound `u32: std::future::Future` is not satisfied
+error[E0277]: `u32` is not a future
   --> $DIR/issues-71798.rs:1:25
    |
 LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `u32`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
 LL |     *x
    |     -- this returned value is of type `u32`
    |
+   = help: the trait `std::future::Future` is not implemented for `u32`
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr
index 2283b1275d018..b759aa45e3eb7 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 ccaa6334856b4..4fb805b37e03f 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 734ae78f362db..20335d2cdd684 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 6cfed20f43a04..b4cc1a0aa7eb2 100644
--- a/src/test/ui/issues/issue-34721.stderr
+++ b/src/test/ui/issues/issue-34721.stderr
@@ -5,14 +5,19 @@ LL |     pub fn baz<T: Foo>(x: T) -> T {
    |                        - move occurs because `x` has type `T`, which does not implement the `Copy` trait
 LL |         if 0 == 1 {
 LL |             bar::bar(x.zero())
-   |                      - value moved here
+   |                        ------ `x` moved due to this method call
 LL |         } else {
 LL |             x.zero()
-   |             - value moved here
+   |               ------ `x` moved due to this method call
 LL |         };
 LL |         x.zero()
    |         ^ value used here after move
    |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $DIR/issue-34721.rs:4:13
+   |
+LL |     fn zero(self) -> Self;
+   |             ^^^^
 help: consider further restricting this bound
    |
 LL |     pub fn baz<T: Foo + Copy>(x: T) -> T {
diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr
index 8523a6f6548a6..ba43f2d33ee44 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 3c685dc8d089a..2c337bae13017 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 0000000000000..6107f53fa1960
--- /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 0000000000000..4333e8a23e866
--- /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 71a3c4506eaf2..142feb280d153 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 67fae606c4e43..ff98aab50c9f8 100644
--- a/src/test/ui/moves/moves-based-on-type-exprs.stderr
+++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr
@@ -104,9 +104,15 @@ error[E0382]: borrow of moved value: `x`
 LL |     let x = vec!["hi".to_string()];
    |         - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
 LL |     let _y = x.into_iter().next().unwrap();
-   |              - value moved here
+   |                ----------- `x` moved due to this method call
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:83:11
@@ -114,9 +120,15 @@ error[E0382]: borrow of moved value: `x`
 LL |     let x = vec!["hi".to_string()];
    |         - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
 LL |     let _y = [x.into_iter().next().unwrap(); 1];
-   |               - value moved here
+   |                 ----------- `x` moved due to this method call
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+  --> $SRC_DIR/libcore/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/once-cant-call-twice-on-heap.stderr b/src/test/ui/once-cant-call-twice-on-heap.stderr
index 7133a32431a67..8761b5261d51b 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/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 99ba4e2a646e5..11372494772d0 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied
+error[E0277]: `fn() -> impl std::future::Future {foo}` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9
    |
 LL | async fn foo() {}
@@ -8,14 +8,15 @@ LL | fn bar(f: impl Future<Output=()>) {}
    |                ----------------- required by this bound in `bar`
 ...
 LL |     bar(foo);
-   |         ^^^ the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
+   |         ^^^ `fn() -> impl std::future::Future {foo}` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
 help: use parentheses to call the function
    |
 LL |     bar(foo());
    |            ^^
 
-error[E0277]: the trait bound `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]: std::future::Future` is not satisfied
+error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
    |
 LL | fn bar(f: impl Future<Output=()>) {}
@@ -24,8 +25,9 @@ LL | fn bar(f: impl Future<Output=()>) {}
 LL |     let async_closure = async || ();
    |                         -------- consider calling this closure
 LL |     bar(async_closure);
-   |         ^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+   |         ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
 help: use parentheses to call the closure
    |
 LL |     bar(async_closure());
diff --git a/src/test/ui/terminal-width/flag-human.rs b/src/test/ui/terminal-width/flag-human.rs
new file mode 100644
index 0000000000000..e445a84fd012e
--- /dev/null
+++ b/src/test/ui/terminal-width/flag-human.rs
@@ -0,0 +1,9 @@
+// compile-flags: -Z terminal-width=20
+
+// This test checks that `-Z terminal-width` effects the human error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+    let _: () = 42;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/terminal-width/flag-human.stderr b/src/test/ui/terminal-width/flag-human.stderr
new file mode 100644
index 0000000000000..393dcf2b82845
--- /dev/null
+++ b/src/test/ui/terminal-width/flag-human.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/flag-human.rs:7:17
+   |
+LL | ..._: () = 42;
+   |       --   ^^ expected `()`, found integer
+   |       |
+   |       expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/terminal-width/flag-json.rs b/src/test/ui/terminal-width/flag-json.rs
new file mode 100644
index 0000000000000..eabdc59ddedd5
--- /dev/null
+++ b/src/test/ui/terminal-width/flag-json.rs
@@ -0,0 +1,9 @@
+// compile-flags: -Z terminal-width=20 --error-format=json
+
+// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+    let _: () = 42;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/terminal-width/flag-json.stderr b/src/test/ui/terminal-width/flag-json.stderr
new file mode 100644
index 0000000000000..29730ccdd4ed7
--- /dev/null
+++ b/src/test/ui/terminal-width/flag-json.stderr
@@ -0,0 +1,32 @@
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code example:
+
+```compile_fail,E0308
+let x: i32 = \"I am not a number!\";
+//     ~~~   ~~~~~~~~~~~~~~~~~~~~
+//      |             |
+//      |    initializing expression;
+//      |    compiler infers type `&str`
+//      |
+//    type `i32` assigned to variable `x`
+```
+
+This error occurs when the compiler is unable to infer the concrete type of a
+variable. It can occur in several cases, the most common being a mismatch
+between two types: the type the author explicitly assigned, and the type the
+compiler inferred.
+"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":"    let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":"    let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
+  --> $DIR/flag-json.rs:7:17
+   |
+LL | ..._: () = 42;
+   |       --   ^^ expected `()`, found integer
+   |       |
+   |       expected due to this
+
+"}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
+
+"}
+{"message":"For more information about this error, try `rustc --explain E0308`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0308`.
+"}
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 0b9aa61a765fa..ab6f06518467c 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 20773d561f9f2..8d70a2b17602b 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 e0499cfe95ce9..dd54c222f64bb 100644
--- a/src/test/ui/unop-move-semantics.stderr
+++ b/src/test/ui/unop-move-semantics.stderr
@@ -4,11 +4,16 @@ error[E0382]: borrow of moved value: `x`
 LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
    |                                               - move occurs because `x` has type `T`, which does not implement the `Copy` trait
 LL |     !x;
-   |      - value moved here
+   |     -- `x` moved due to usage in operator
 LL | 
 LL |     x.clone();
    |     ^ value borrowed here after move
    |
+note: calling this operator moves the left-hand side
+  --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
+   |
+LL |     fn not(self) -> Self::Output;
+   |            ^^^^
 help: consider further restricting this bound
    |
 LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr
index 110edab69be87..906b543e42122 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 5b936fb64474f..49b2031c6b9d9 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 9bf1175430c84..b9440f4de07a9 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 3be0a65550b7f..3da53b024db44 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 eeb594a21f38c..ece63a2b81947 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
 
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 7d2c83881d13b..571e7a59113ad 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -263,7 +263,7 @@ impl EarlyProps {
         }
 
         fn version_to_int(version: &str) -> u32 {
-            let version_without_suffix = version.split('-').next().unwrap();
+            let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
             let components: Vec<u32> = version_without_suffix
                 .split('.')
                 .map(|s| s.parse().expect("Malformed version component"))