about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_arena/src/lib.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs137
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs24
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs53
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs28
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs15
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs183
-rw-r--r--compiler/rustc_driver/src/lib.rs7
-rw-r--r--compiler/rustc_errors/src/emitter.rs17
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs427
-rw-r--r--compiler/rustc_feature/src/lib.rs2
-rw-r--r--compiler/rustc_hir/src/arena.rs76
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/pat_util.rs11
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs73
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs24
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs6
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs9
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/tests.rs13
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp18
-rw-r--r--compiler/rustc_macros/src/serialize.rs25
-rw-r--r--compiler/rustc_middle/src/arena.rs30
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs2
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs61
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs18
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs68
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs101
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs23
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs21
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs73
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs8
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs6
-rw-r--r--compiler/rustc_passes/src/check_attr.rs127
-rw-r--r--compiler/rustc_query_system/src/lib.rs1
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs97
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs16
-rw-r--r--compiler/rustc_resolve/src/imports.rs50
-rw-r--r--compiler/rustc_resolve/src/macros.rs1
-rw-r--r--compiler/rustc_serialize/src/json.rs14
-rw-r--r--compiler/rustc_serialize/src/serialize.rs14
-rw-r--r--compiler/rustc_session/src/config.rs20
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs16
-rw-r--r--compiler/rustc_session/src/session.rs21
-rw-r--r--compiler/rustc_span/src/hygiene.rs11
-rw-r--r--compiler/rustc_span/src/lib.rs3
-rw-r--r--compiler/rustc_span/src/source_map.rs19
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/spec/mod.rs60
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs4
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs7
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs12
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs36
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs83
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs46
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs5
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs24
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs10
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs26
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs188
-rw-r--r--compiler/rustc_typeck/src/collect.rs24
83 files changed, 1795 insertions, 924 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index e54fcaf6fc1..6f9ecb9cd21 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -111,7 +111,7 @@ impl<T> Default for TypedArena<T> {
             // alloc() will trigger a grow().
             ptr: Cell::new(ptr::null_mut()),
             end: Cell::new(ptr::null_mut()),
-            chunks: RefCell::new(vec![]),
+            chunks: Default::default(),
             _own: PhantomData,
         }
     }
@@ -325,13 +325,17 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
 
 unsafe impl<T: Send> Send for TypedArena<T> {}
 
+/// An arena that can hold objects of multiple different types that impl `Copy`
+/// and/or satisfy `!mem::needs_drop`.
 pub struct DroplessArena {
     /// A pointer to the start of the free space.
     start: Cell<*mut u8>,
 
     /// A pointer to the end of free space.
     ///
-    /// The allocation proceeds from the end of the chunk towards the start.
+    /// The allocation proceeds downwards from the end of the chunk towards the
+    /// start. (This is slightly simpler and faster than allocating upwards,
+    /// see <https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html>.)
     /// When this pointer crosses the start pointer, a new chunk is allocated.
     end: Cell<*mut u8>,
 
@@ -516,10 +520,14 @@ impl DroplessArena {
     }
 }
 
+// Declare an `Arena` containing one dropless arena and many typed arenas (the
+// types of the typed arenas are specified by the arguments). The dropless
+// arena will be used for any types that impl `Copy`, and also for any of the
+// specified types that satisfy `!mem::needs_drop`.
 #[rustc_macro_transparency = "semitransparent"]
-pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
+pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
     #[derive(Default)]
-    pub struct Arena<$tcx> {
+    pub struct Arena<'tcx> {
         pub dropless: $crate::DroplessArena,
         $($name: $crate::TypedArena<$ty>,)*
     }
@@ -532,6 +540,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
         ) -> &'a mut [Self];
     }
 
+    // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
     impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
         #[inline]
         fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
@@ -544,12 +553,11 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
         ) -> &'a mut [Self] {
             arena.dropless.alloc_from_iter(iter)
         }
-
     }
     $(
-        impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
+        impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty {
             #[inline]
-            fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
+            fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
                 if !::std::mem::needs_drop::<Self>() {
                     arena.dropless.alloc(self)
                 } else {
@@ -559,7 +567,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
 
             #[inline]
             fn allocate_from_iter<'a>(
-                arena: &'a Arena<$tcx>,
+                arena: &'a Arena<'tcx>,
                 iter: impl ::std::iter::IntoIterator<Item = Self>,
             ) -> &'a mut [Self] {
                 if !::std::mem::needs_drop::<Self>() {
@@ -577,6 +585,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
             value.allocate_on(self)
         }
 
+        // Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`.
         #[inline]
         pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
             if value.is_empty() {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 405e9035c4c..a0a63620c08 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -13,7 +13,7 @@ use rustc_session::parse::feature_err;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -1308,16 +1308,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
     /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
     /// ```rust
     /// {
-    ///     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
+    ///     let result = match IntoIterator::into_iter(<head>) {
     ///         mut iter => {
     ///             [opt_ident]: loop {
-    ///                 let mut __next;
-    ///                 match ::std::iter::Iterator::next(&mut iter) {
-    ///                     ::std::option::Option::Some(val) => __next = val,
-    ///                     ::std::option::Option::None => break
+    ///                 match Iterator::next(&mut iter) {
+    ///                     None => break,
+    ///                     Some(<pat>) => <body>,
     ///                 };
-    ///                 let <pat> = __next;
-    ///                 StmtKind::Expr(<body>);
     ///             }
     ///         }
     ///     };
@@ -1332,133 +1329,75 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Block,
         opt_label: Option<Label>,
     ) -> hir::Expr<'hir> {
-        // expand <head>
         let head = self.lower_expr_mut(head);
-        let desugared_span =
-            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None);
-        let e_span = self.lower_span(e.span);
-
-        let iter = Ident::with_dummy_span(sym::iter);
-
-        let next_ident = Ident::with_dummy_span(sym::__next);
-        let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
-            desugared_span,
-            next_ident,
-            hir::BindingAnnotation::Mutable,
-        );
-
-        // `::std::option::Option::Some(val) => __next = val`
-        let pat_arm = {
-            let val_ident = Ident::with_dummy_span(sym::val);
-            let pat_span = self.lower_span(pat.span);
-            let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident);
-            let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid);
-            let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid);
-            let assign = self.arena.alloc(self.expr(
-                pat_span,
-                hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)),
-                ThinVec::new(),
-            ));
-            let some_pat = self.pat_some(pat_span, val_pat);
-            self.arm(some_pat, assign)
-        };
+        let pat = self.lower_pat(pat);
+        let for_span =
+            self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
+        let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
+        let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
 
-        // `::std::option::Option::None => break`
-        let break_arm = {
+        // `None => break`
+        let none_arm = {
             let break_expr =
-                self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new()));
-            let pat = self.pat_none(e_span);
+                self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
+            let pat = self.pat_none(for_span);
             self.arm(pat, break_expr)
         };
 
+        // Some(<pat>) => <body>,
+        let some_arm = {
+            let some_pat = self.pat_some(pat_span, pat);
+            let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
+            let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
+            self.arm(some_pat, body_expr)
+        };
+
         // `mut iter`
+        let iter = Ident::with_dummy_span(sym::iter);
         let (iter_pat, iter_pat_nid) =
-            self.pat_ident_binding_mode(desugared_span, iter, hir::BindingAnnotation::Mutable);
+            self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
 
-        // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+        // `match Iterator::next(&mut iter) { ... }`
         let match_expr = {
-            let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
-            let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
+            let iter = self.expr_ident(head_span, iter, iter_pat_nid);
+            let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
             let next_expr = self.expr_call_lang_item_fn(
-                desugared_span,
+                head_span,
                 hir::LangItem::IteratorNext,
                 arena_vec![self; ref_mut_iter],
             );
-            let arms = arena_vec![self; pat_arm, break_arm];
+            let arms = arena_vec![self; none_arm, some_arm];
 
-            self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
+            self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
         };
-        let match_stmt = self.stmt_expr(desugared_span, match_expr);
-
-        let next_expr = self.expr_ident(desugared_span, next_ident, next_pat_hid);
-
-        // `let mut __next`
-        let next_let = self.stmt_let_pat(
-            None,
-            desugared_span,
-            None,
-            next_pat,
-            hir::LocalSource::ForLoopDesugar,
-        );
+        let match_stmt = self.stmt_expr(for_span, match_expr);
 
-        // `let <pat> = __next`
-        let pat = self.lower_pat(pat);
-        let pat_let = self.stmt_let_pat(
-            None,
-            desugared_span,
-            Some(next_expr),
-            pat,
-            hir::LocalSource::ForLoopDesugar,
-        );
-
-        let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
-        let body_expr = self.expr_block(body_block, ThinVec::new());
-        let body_stmt = self.stmt_expr(body_block.span, body_expr);
-
-        let loop_block = self.block_all(
-            e_span,
-            arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
-            None,
-        );
+        let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);
 
         // `[opt_ident]: loop { ... }`
         let kind = hir::ExprKind::Loop(
             loop_block,
             self.lower_label(opt_label),
             hir::LoopSource::ForLoop,
-            self.lower_span(e_span.with_hi(head.span.hi())),
+            self.lower_span(for_span.with_hi(head.span.hi())),
         );
-        let loop_expr = self.arena.alloc(hir::Expr {
-            hir_id: self.lower_node_id(e.id),
-            kind,
-            span: self.lower_span(e.span),
-        });
+        let loop_expr =
+            self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
 
         // `mut iter => { ... }`
         let iter_arm = self.arm(iter_pat, loop_expr);
 
-        let into_iter_span = self.mark_span_with_reason(
-            DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
-            head.span,
-            None,
-        );
-
         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
         let into_iter_expr = {
             self.expr_call_lang_item_fn(
-                into_iter_span,
+                head_span,
                 hir::LangItem::IntoIterIntoIter,
                 arena_vec![self; head],
             )
         };
 
-        // #82462: to correctly diagnose borrow errors, the block that contains
-        // the iter expr needs to have a span that covers the loop body.
-        let desugared_full_span =
-            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None);
-
         let match_expr = self.arena.alloc(self.expr_match(
-            desugared_full_span,
+            for_span,
             into_iter_expr,
             arena_vec![self; iter_arm],
             hir::MatchSource::ForLoopDesugar,
@@ -1472,7 +1411,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into())
+        self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index fef6e87bfdb..2b3a538772e 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -84,7 +84,7 @@ mod item;
 mod pat;
 mod path;
 
-rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx);
+rustc_hir::arena_types!(rustc_arena::declare_arena);
 
 struct LoweringContext<'a, 'hir: 'a> {
     /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index b011a2e8117..6a19984f8ea 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -719,6 +719,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(const_trait_impl, "const trait impls are experimental");
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
+    gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
     gate_all!(
         const_generics_defaults,
         "default values for const generic parameters are experimental"
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 79973ab170c..db8268c8e2e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::{self, RegionVid, TyCtxt};
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{sym, DesugaringKind, Span};
 
 use crate::region_infer::BlameConstraint;
 use crate::{
@@ -135,7 +135,16 @@ impl BorrowExplanation {
                 should_note_order,
             } => {
                 let local_decl = &body.local_decls[dropped_local];
-                let (dtor_desc, type_desc) = match local_decl.ty.kind() {
+                let mut ty = local_decl.ty;
+                if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+                    if let ty::Adt(adt, substs) = local_decl.ty.kind() {
+                        if tcx.is_diagnostic_item(sym::Option, adt.did) {
+                            // in for loop desugaring, only look at the `Some(..)` inner type
+                            ty = substs.type_at(0);
+                        }
+                    }
+                }
+                let (dtor_desc, type_desc) = match ty.kind() {
                     // If type is an ADT that implements Drop, then
                     // simplify output by reporting just the ADT name.
                     ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index a4df277a7b0..79623e26eb7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,11 +13,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{
-    hygiene::{DesugaringKind, ForLoopLoc},
-    symbol::sym,
-    Span,
-};
+use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
@@ -955,10 +951,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let kind = kind.unwrap_or_else(|| {
                 // This isn't a 'special' use of `self`
                 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))
-                );
+                let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
+                    && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
                 let parent_self_ty = parent
                     .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
                     .and_then(|did| match tcx.type_of(did).kind() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index d5ff4c6766f..46e2a99a0d0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -445,15 +445,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 },
                             ))) => {
                                 // check if the RHS is from desugaring
-                                let locations = self.body.find_assignments(local);
-                                let opt_assignment_rhs_span = locations
-                                    .first()
-                                    .map(|&location| self.body.source_info(location).span);
-                                let opt_desugaring_kind =
-                                    opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
-                                match opt_desugaring_kind {
+                                let opt_assignment_rhs_span =
+                                    self.body.find_assignments(local).first().map(|&location| {
+                                        let stmt = &self.body[location.block].statements
+                                            [location.statement_index];
+                                        match stmt.kind {
+                                            mir::StatementKind::Assign(box (
+                                                _,
+                                                mir::Rvalue::Use(mir::Operand::Copy(place)),
+                                            )) => {
+                                                self.body.local_decls[place.local].source_info.span
+                                            }
+                                            _ => self.body.source_info(location).span,
+                                        }
+                                    });
+                                match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
                                     // on for loops, RHS points to the iterator part
-                                    Some(DesugaringKind::ForLoop(_)) => {
+                                    Some(DesugaringKind::ForLoop) => {
                                         self.suggest_similar_mut_method_for_for_loop(&mut err);
                                         Some((
                                             false,
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 659cf9ea070..8e6329a997f 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::OptLevel;
 use rustc_session::Session;
 use rustc_target::spec::abi::Abi;
-use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
+use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 
 use crate::attributes;
 use crate::llvm::AttributePlace::Function;
@@ -161,6 +161,17 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     }
 }
 
+fn set_stackprotector(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+    let sspattr = match cx.sess().stack_protector() {
+        StackProtector::None => return,
+        StackProtector::All => Attribute::StackProtectReq,
+        StackProtector::Strong => Attribute::StackProtectStrong,
+        StackProtector::Basic => Attribute::StackProtect,
+    };
+
+    sspattr.apply_llfn(Function, llfn)
+}
+
 pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess));
     llvm::AddFunctionAttrStringValue(
@@ -271,6 +282,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     set_frame_pointer_type(cx, llfn);
     set_instrument_function(cx, llfn);
     set_probestack(cx, llfn);
+    set_stackprotector(cx, llfn);
 
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
         Attribute::Cold.apply_llfn(Function, llfn);
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 64fedb7bc1a..c66d7d872c9 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -288,6 +288,31 @@ impl CodegenBackend for LlvmCodegenBackend {
                 }
                 println!();
             }
+            PrintRequest::StackProtectorStrategies => {
+                println!(
+                    r#"Available stack protector strategies:
+    all
+        Generate stack canaries in all functions.
+
+    strong
+        Generate stack canaries in a function if it either:
+        - has a local variable of `[T; N]` type, regardless of `T` and `N`
+        - takes the address of a local variable.
+
+          (Note that a local variable being borrowed is not equivalent to its
+          address being taken: e.g. some borrows may be removed by optimization,
+          while by-value argument passing may be implemented with reference to a
+          local stack variable in the ABI.)
+
+    basic
+        Generate stack canaries in functions with:
+        - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
+
+    none
+        Do not generate stack canaries.
+"#
+                );
+            }
             req => llvm_util::print(req, sess),
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 749eec459ac..1d255c07559 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -166,6 +166,9 @@ pub enum Attribute {
     InaccessibleMemOnly = 27,
     SanitizeHWAddress = 28,
     WillReturn = 29,
+    StackProtectReq = 30,
+    StackProtectStrong = 31,
+    StackProtect = 32,
 }
 
 /// LLVMIntPredicate
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 5e7bbc01132..44da27a43db 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -265,12 +265,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             sym::discriminant_value => {
                 let place = self.deref_operand(&args[0])?;
-                if M::enforce_validity(self) {
-                    // This is 'using' the value, so make sure the validity invariant is satisfied.
-                    // (Also see https://github.com/rust-lang/rust/pull/89764.)
-                    self.validate_operand(&place.into())?;
-                }
-
                 let discr_val = self.read_discriminant(&place.into())?.0;
                 self.write_scalar(discr_val, dest)?;
             }
@@ -419,48 +413,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::simd_insert => {
                 let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
                 let elem = &args[2];
-                let input = &args[0];
-                let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
+                let (input, input_len) = self.operand_to_simd(&args[0])?;
+                let (dest, dest_len) = self.place_to_simd(dest)?;
+                assert_eq!(input_len, dest_len, "Return vector length must match input length");
                 assert!(
-                    index < len,
-                    "Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
+                    index < dest_len,
+                    "Index `{}` must be in bounds of vector with length {}`",
                     index,
-                    e_ty,
-                    len
-                );
-                assert_eq!(
-                    input.layout, dest.layout,
-                    "Return type `{}` must match vector type `{}`",
-                    dest.layout.ty, input.layout.ty
-                );
-                assert_eq!(
-                    elem.layout.ty, e_ty,
-                    "Scalar element type `{}` must match vector element type `{}`",
-                    elem.layout.ty, e_ty
+                    dest_len
                 );
 
-                for i in 0..len {
-                    let place = self.place_index(dest, i)?;
-                    let value = if i == index { *elem } else { self.operand_index(input, i)? };
-                    self.copy_op(&value, &place)?;
+                for i in 0..dest_len {
+                    let place = self.mplace_index(&dest, i)?;
+                    let value =
+                        if i == index { *elem } else { self.mplace_index(&input, i)?.into() };
+                    self.copy_op(&value, &place.into())?;
                 }
             }
             sym::simd_extract => {
                 let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
-                let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
+                let (input, input_len) = self.operand_to_simd(&args[0])?;
                 assert!(
-                    index < len,
-                    "index `{}` is out-of-bounds of vector type `{}` with length `{}`",
+                    index < input_len,
+                    "index `{}` must be in bounds of vector with length `{}`",
                     index,
-                    e_ty,
-                    len
-                );
-                assert_eq!(
-                    e_ty, dest.layout.ty,
-                    "Return type `{}` must match vector element type `{}`",
-                    dest.layout.ty, e_ty
+                    input_len
                 );
-                self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
+                self.copy_op(&self.mplace_index(&input, index)?.into(), dest)?;
             }
             sym::likely | sym::unlikely | sym::black_box => {
                 // These just return their argument
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index b6682b13ed2..de9e94ce2ac 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -437,6 +437,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         })
     }
 
+    /// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements.
+    /// Also returns the number of elements.
+    pub fn operand_to_simd(
+        &self,
+        base: &OpTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+        // Basically we just transmute this place into an array following simd_size_and_type.
+        // This only works in memory, but repr(simd) types should never be immediates anyway.
+        assert!(base.layout.ty.is_simd());
+        self.mplace_to_simd(&base.assert_mem_place())
+    }
+
     /// Read from a local. Will not actually access the local if reading from a ZST.
     /// Will not access memory, instead an indirect `Operand` is returned.
     ///
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index d425b84bdaf..d7f2853fc86 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -200,7 +200,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
             }
         } else {
             // Go through the layout.  There are lots of types that support a length,
-            // e.g., SIMD types.
+            // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!)
             match self.layout.fields {
                 FieldsShape::Array { count, .. } => Ok(count),
                 _ => bug!("len not supported on sized type {:?}", self.layout.ty),
@@ -533,6 +533,22 @@ where
         })
     }
 
+    /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements.
+    /// Also returns the number of elements.
+    pub fn mplace_to_simd(
+        &self,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+        // Basically we just transmute this place into an array following simd_size_and_type.
+        // (Transmuting is okay since this is an in-memory place. We also double-check the size
+        // stays the same.)
+        let (len, e_ty) = base.layout.ty.simd_size_and_type(*self.tcx);
+        let array = self.tcx.mk_array(e_ty, len);
+        let layout = self.layout_of(array)?;
+        assert_eq!(layout.size, base.layout.size);
+        Ok((MPlaceTy { layout, ..*base }, len))
+    }
+
     /// Gets the place of a field inside the place, and also the field's type.
     /// Just a convenience function, but used quite a bit.
     /// This is the only projection that might have a side-effect: We cannot project
@@ -594,6 +610,16 @@ where
         })
     }
 
+    /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements.
+    /// Also returns the number of elements.
+    pub fn place_to_simd(
+        &mut self,
+        base: &PlaceTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> {
+        let mplace = self.force_allocation(base)?;
+        self.mplace_to_simd(&mplace)
+    }
+
     /// Computes a place. You should only use this if you intend to write into this
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
     pub fn eval_place(
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 2759a7d9d26..e6037d561de 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -304,12 +304,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             Discriminant(place) => {
                 let op = self.eval_place_to_op(place, None)?;
-                if M::enforce_validity(self) {
-                    // This is 'using' the value, so make sure the validity invariant is satisfied.
-                    // (Also see https://github.com/rust-lang/rust/pull/89764.)
-                    self.validate_operand(&op)?;
-                }
-
                 let discr_val = self.read_discriminant(&op)?.0;
                 self.write_scalar(discr_val, &dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index fcce829eba4..b70b38754c9 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -264,7 +264,7 @@ where
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 pub(super) struct State {
     /// Describes whether a local contains qualif.
     pub qualif: BitSet<Local>,
@@ -273,6 +273,19 @@ pub(super) struct State {
     pub borrow: BitSet<Local>,
 }
 
+impl Clone for State {
+    fn clone(&self) -> Self {
+        State { qualif: self.qualif.clone(), borrow: self.borrow.clone() }
+    }
+
+    // Data flow engine when possible uses `clone_from` for domain values.
+    // Providing an implementation will avoid some intermediate memory allocations.
+    fn clone_from(&mut self, other: &Self) {
+        self.qualif.clone_from(&other.qualif);
+        self.borrow.clone_from(&other.borrow);
+    }
+}
+
 impl State {
     #[inline]
     pub(super) fn contains(&self, local: Local) -> bool {
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 7bf378601e0..a92b20f5cb5 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -93,17 +93,8 @@ impl TempState {
 /// returned value in a promoted MIR, unless it's a subset
 /// of a larger candidate.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Candidate {
-    /// Borrow of a constant temporary, candidate for lifetime extension.
-    Ref(Location),
-}
-
-impl Candidate {
-    fn source_info(&self, body: &Body<'_>) -> SourceInfo {
-        match self {
-            Candidate::Ref(location) => *body.source_info(*location),
-        }
-    }
+pub struct Candidate {
+    location: Location,
 }
 
 struct Collector<'a, 'tcx> {
@@ -167,7 +158,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
 
         match *rvalue {
             Rvalue::Ref(..) => {
-                self.candidates.push(Candidate::Ref(location));
+                self.candidates.push(Candidate { location });
             }
             _ => {}
         }
@@ -209,36 +200,33 @@ struct Unpromotable;
 
 impl<'tcx> Validator<'_, 'tcx> {
     fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
-        match candidate {
-            Candidate::Ref(loc) => {
-                let statement = &self.body[loc.block].statements[loc.statement_index];
-                match &statement.kind {
-                    StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
-                        // We can only promote interior borrows of promotable temps (non-temps
-                        // don't get promoted anyway).
-                        self.validate_local(place.local)?;
-
-                        // The reference operation itself must be promotable.
-                        // (Needs to come after `validate_local` to avoid ICEs.)
-                        self.validate_ref(*kind, place)?;
-
-                        // We do not check all the projections (they do not get promoted anyway),
-                        // but we do stay away from promoting anything involving a dereference.
-                        if place.projection.contains(&ProjectionElem::Deref) {
-                            return Err(Unpromotable);
-                        }
+        let loc = candidate.location;
+        let statement = &self.body[loc.block].statements[loc.statement_index];
+        match &statement.kind {
+            StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
+                // We can only promote interior borrows of promotable temps (non-temps
+                // don't get promoted anyway).
+                self.validate_local(place.local)?;
+
+                // The reference operation itself must be promotable.
+                // (Needs to come after `validate_local` to avoid ICEs.)
+                self.validate_ref(*kind, place)?;
 
-                        // We cannot promote things that need dropping, since the promoted value
-                        // would not get dropped.
-                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
-                            return Err(Unpromotable);
-                        }
+                // We do not check all the projections (they do not get promoted anyway),
+                // but we do stay away from promoting anything involving a dereference.
+                if place.projection.contains(&ProjectionElem::Deref) {
+                    return Err(Unpromotable);
+                }
 
-                        Ok(())
-                    }
-                    _ => bug!(),
+                // We cannot promote things that need dropping, since the promoted value
+                // would not get dropped.
+                if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
+                    return Err(Unpromotable);
                 }
+
+                Ok(())
             }
+            _ => bug!(),
         }
     }
 
@@ -871,58 +859,55 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 }))
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
-            match candidate {
-                Candidate::Ref(loc) => {
-                    let statement = &mut blocks[loc.block].statements[loc.statement_index];
-                    match statement.kind {
-                        StatementKind::Assign(box (
-                            _,
-                            Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
-                        )) => {
-                            // Use the underlying local for this (necessarily interior) borrow.
-                            let ty = local_decls.local_decls()[place.local].ty;
-                            let span = statement.source_info.span;
-
-                            let ref_ty = tcx.mk_ref(
-                                tcx.lifetimes.re_erased,
-                                ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
-                            );
-
-                            *region = tcx.lifetimes.re_erased;
-
-                            let mut projection = vec![PlaceElem::Deref];
-                            projection.extend(place.projection);
-                            place.projection = tcx.intern_place_elems(&projection);
-
-                            // Create a temp to hold the promoted reference.
-                            // This is because `*r` requires `r` to be a local,
-                            // otherwise we would use the `promoted` directly.
-                            let mut promoted_ref = LocalDecl::new(ref_ty, span);
-                            promoted_ref.source_info = statement.source_info;
-                            let promoted_ref = local_decls.push(promoted_ref);
-                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
-
-                            let promoted_ref_statement = Statement {
-                                source_info: statement.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    Place::from(promoted_ref),
-                                    Rvalue::Use(promoted_operand(ref_ty, span)),
-                                ))),
-                            };
-                            self.extra_statements.push((loc, promoted_ref_statement));
-
-                            Rvalue::Ref(
-                                tcx.lifetimes.re_erased,
-                                borrow_kind,
-                                Place {
-                                    local: mem::replace(&mut place.local, promoted_ref),
-                                    projection: List::empty(),
-                                },
-                            )
-                        }
-                        _ => bug!(),
-                    }
+            let loc = candidate.location;
+            let statement = &mut blocks[loc.block].statements[loc.statement_index];
+            match statement.kind {
+                StatementKind::Assign(box (
+                    _,
+                    Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
+                )) => {
+                    // Use the underlying local for this (necessarily interior) borrow.
+                    let ty = local_decls.local_decls()[place.local].ty;
+                    let span = statement.source_info.span;
+
+                    let ref_ty = tcx.mk_ref(
+                        tcx.lifetimes.re_erased,
+                        ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
+                    );
+
+                    *region = tcx.lifetimes.re_erased;
+
+                    let mut projection = vec![PlaceElem::Deref];
+                    projection.extend(place.projection);
+                    place.projection = tcx.intern_place_elems(&projection);
+
+                    // Create a temp to hold the promoted reference.
+                    // This is because `*r` requires `r` to be a local,
+                    // otherwise we would use the `promoted` directly.
+                    let mut promoted_ref = LocalDecl::new(ref_ty, span);
+                    promoted_ref.source_info = statement.source_info;
+                    let promoted_ref = local_decls.push(promoted_ref);
+                    assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+
+                    let promoted_ref_statement = Statement {
+                        source_info: statement.source_info,
+                        kind: StatementKind::Assign(Box::new((
+                            Place::from(promoted_ref),
+                            Rvalue::Use(promoted_operand(ref_ty, span)),
+                        ))),
+                    };
+                    self.extra_statements.push((loc, promoted_ref_statement));
+
+                    Rvalue::Ref(
+                        tcx.lifetimes.re_erased,
+                        borrow_kind,
+                        Place {
+                            local: mem::replace(&mut place.local, promoted_ref),
+                            projection: List::empty(),
+                        },
+                    )
                 }
+                _ => bug!(),
             }
         };
 
@@ -964,17 +949,13 @@ pub fn promote_candidates<'tcx>(
 
     let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
-        match candidate {
-            Candidate::Ref(Location { block, statement_index }) => {
-                if let StatementKind::Assign(box (place, _)) =
-                    &body[block].statements[statement_index].kind
-                {
-                    if let Some(local) = place.as_local() {
-                        if temps[local] == TempState::PromotedOut {
-                            // Already promoted.
-                            continue;
-                        }
-                    }
+        let Location { block, statement_index } = candidate.location;
+        if let StatementKind::Assign(box (place, _)) = &body[block].statements[statement_index].kind
+        {
+            if let Some(local) = place.as_local() {
+                if temps[local] == TempState::PromotedOut {
+                    // Already promoted.
+                    continue;
                 }
             }
         }
@@ -982,7 +963,7 @@ pub fn promote_candidates<'tcx>(
         // Declare return place local so that `mir::Body::new` doesn't complain.
         let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect();
 
-        let mut scope = body.source_scopes[candidate.source_info(body).scope].clone();
+        let mut scope = body.source_scopes[body.source_info(candidate.location).scope].clone();
         scope.parent_scope = None;
 
         let promoted = Body::new(
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 09fe3a552a0..6ff94341142 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -736,7 +736,12 @@ impl RustcDefaultCalls {
                         println!("{}", cfg);
                     }
                 }
-                RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
+                RelocationModels
+                | CodeModels
+                | TlsModels
+                | TargetCPUs
+                | StackProtectorStrategies
+                | TargetFeatures => {
                     codegen_backend.print(*req, sess);
                 }
                 // Any output here interferes with Cargo's parsing of other printed output
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index e16ff974122..6b79962ddd6 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1266,22 +1266,37 @@ impl EmitterWriter {
             }
             self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
         } else {
+            let mut label_width = 0;
             // The failure note level itself does not provide any useful diagnostic information
             if *level != Level::FailureNote {
                 buffer.append(0, level.to_str(), Style::Level(*level));
+                label_width += level.to_str().len();
             }
             // only render error codes, not lint codes
             if let Some(DiagnosticId::Error(ref code)) = *code {
                 buffer.append(0, "[", Style::Level(*level));
                 buffer.append(0, &code, Style::Level(*level));
                 buffer.append(0, "]", Style::Level(*level));
+                label_width += 2 + code.len();
             }
             let header_style = if is_secondary { Style::HeaderMsg } else { Style::MainHeaderMsg };
             if *level != Level::FailureNote {
                 buffer.append(0, ": ", header_style);
+                label_width += 2;
             }
             for &(ref text, _) in msg.iter() {
-                buffer.append(0, &replace_tabs(text), header_style);
+                // Account for newlines to align output to its label.
+                for (line, text) in replace_tabs(text).lines().enumerate() {
+                    buffer.append(
+                        0 + line,
+                        &format!(
+                            "{}{}",
+                            if line == 0 { String::new() } else { " ".repeat(label_width) },
+                            text
+                        ),
+                        header_style,
+                    );
+                }
             }
         }
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 608581306be..c34ecc966d0 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -409,7 +409,9 @@ declare_features! (
     /// Allows associated types in inherent impls.
     (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
     /// Allow anonymous constants from an inline `const` block
-    (incomplete, inline_const, "1.49.0", Some(76001), None),
+    (active, inline_const, "1.49.0", Some(76001), None),
+    /// Allow anonymous constants from an inline `const` block in pattern position
+    (incomplete, inline_const_pat, "1.58.0", Some(76001), None),
     /// Allows using `pointer` and `reference` in intra-doc links
     (active, intra_doc_pointers, "1.51.0", Some(80896), None),
     /// Allows `#[instruction_set(_)]` attribute
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 74a637fde33..f25b2d8f566 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1,5 +1,6 @@
 //! Built-in attributes and `cfg` flag gating.
 
+use AttributeDuplicates::*;
 use AttributeGate::*;
 use AttributeType::*;
 
@@ -88,11 +89,66 @@ impl AttributeGate {
 /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
 #[derive(Clone, Copy, Default)]
 pub struct AttributeTemplate {
+    /// If `true`, the attribute is allowed to be a bare word like `#[test]`.
     pub word: bool,
+    /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
     pub list: Option<&'static str>,
+    /// If `Some`, the attribute is allowed to be a name/value pair where the
+    /// value is a string, like `#[must_use = "reason"]`.
     pub name_value_str: Option<&'static str>,
 }
 
+/// How to handle multiple duplicate attributes on the same item.
+#[derive(Clone, Copy, Default)]
+pub enum AttributeDuplicates {
+    /// Duplicates of this attribute are allowed.
+    ///
+    /// This should only be used with attributes where duplicates have semantic
+    /// meaning, or some kind of "additive" behavior. For example, `#[warn(..)]`
+    /// can be specified multiple times, and it combines all the entries. Or use
+    /// this if there is validation done elsewhere.
+    #[default]
+    DuplicatesOk,
+    /// Duplicates after the first attribute will be an unused_attribute warning.
+    ///
+    /// This is usually used for "word" attributes, where they are used as a
+    /// boolean marker, like `#[used]`. It is not necessarily wrong that there
+    /// are duplicates, but the others should probably be removed.
+    WarnFollowing,
+    /// Same as `WarnFollowing`, but only issues warnings for word-style attributes.
+    ///
+    /// This is only for special cases, for example multiple `#[macro_use]` can
+    /// be warned, but multiple `#[macro_use(...)]` should not because the list
+    /// form has different meaning from the word form.
+    WarnFollowingWordOnly,
+    /// Duplicates after the first attribute will be an error.
+    ///
+    /// This should be used where duplicates would be ignored, but carry extra
+    /// meaning that could cause confusion. For example, `#[stable(since="1.0")]
+    /// #[stable(since="2.0")]`, which version should be used for `stable`?
+    ErrorFollowing,
+    /// Duplicates preceding the last instance of the attribute will be an error.
+    ///
+    /// This is the same as `ErrorFollowing`, except the last attribute is the
+    /// one that is "used". This is typically used in cases like codegen
+    /// attributes which usually only honor the last attribute.
+    ErrorPreceding,
+    /// Duplicates after the first attribute will be an unused_attribute warning
+    /// with a note that this will be an error in the future.
+    ///
+    /// This should be used for attributes that should be `ErrorFollowing`, but
+    /// because older versions of rustc silently accepted (and ignored) the
+    /// attributes, this is used to transition.
+    FutureWarnFollowing,
+    /// Duplicates preceding the last instance of the attribute will be a
+    /// warning, with a note that this will be an error in the future.
+    ///
+    /// This is the same as `FutureWarnFollowing`, except the last attribute is
+    /// the one that is "used". Ideally these can eventually migrate to
+    /// `ErrorPreceding`.
+    FutureWarnPreceding,
+}
+
 /// A convenience macro for constructing attribute templates.
 /// E.g., `template!(Word, List: "description")` means that the attribute
 /// supports forms `#[attr]` and `#[attr(description)]`.
@@ -114,36 +170,45 @@ macro_rules! template {
 }
 
 macro_rules! ungated {
-    ($attr:ident, $typ:expr, $tpl:expr $(,)?) => {
-        BuiltinAttribute { name: sym::$attr, type_: $typ, template: $tpl, gate: Ungated }
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(,)?) => {
+        BuiltinAttribute {
+            name: sym::$attr,
+            type_: $typ,
+            template: $tpl,
+            gate: Ungated,
+            duplicates: $duplicates,
+        }
     };
 }
 
 macro_rules! gated {
-    ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $gate:ident, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             type_: $typ,
             template: $tpl,
+            duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
         }
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             type_: $typ,
             template: $tpl,
+            duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
         }
     };
 }
 
 macro_rules! rustc_attr {
-    (TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => {
+    (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(,)?) => {
         rustc_attr!(
             $attr,
             $typ,
             $tpl,
+            $duplicate,
             concat!(
                 "the `#[",
                 stringify!($attr),
@@ -152,11 +217,12 @@ macro_rules! rustc_attr {
             ),
         )
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             type_: $typ,
             template: $tpl,
+            duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
         }
     };
@@ -175,6 +241,7 @@ pub struct BuiltinAttribute {
     pub name: Symbol,
     pub type_: AttributeType,
     pub template: AttributeTemplate,
+    pub duplicates: AttributeDuplicates,
     pub gate: AttributeGate,
 }
 
@@ -186,42 +253,48 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     // Conditional compilation:
-    ungated!(cfg, Normal, template!(List: "predicate")),
-    ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")),
+    ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk),
+    ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk),
 
     // Testing:
-    ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")),
+    ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing),
     ungated!(
         should_panic, Normal,
-        template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
+        template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), FutureWarnFollowing,
     ),
     // FIXME(Centril): This can be used on stable but shouldn't.
-    ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name")),
+    ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing),
 
     // Macros:
-    ungated!(automatically_derived, Normal, template!(Word)),
-    // FIXME(#14407)
-    ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
-    ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`.
-    ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")),
-    ungated!(proc_macro, Normal, template!(Word)),
+    ungated!(automatically_derived, Normal, template!(Word), WarnFollowing),
+    ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly),
+    ungated!(macro_escape, Normal, template!(Word), WarnFollowing), // Deprecated synonym for `macro_use`.
+    ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros"), WarnFollowing),
+    ungated!(proc_macro, Normal, template!(Word), ErrorFollowing),
     ungated!(
         proc_macro_derive, Normal,
-        template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"),
+        template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
     ),
-    ungated!(proc_macro_attribute, Normal, template!(Word)),
+    ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing),
 
     // Lints:
-    ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
-    ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
-    ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
-    ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
-    ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
+    ungated!(
+        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+    ),
+    ungated!(
+        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+    ),
+    ungated!(
+        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+    ),
+    ungated!(
+        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+    ),
+    ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
     gated!(
-        must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend,
-        experimental!(must_not_suspend)
+        must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
+        must_not_suspend, experimental!(must_not_suspend)
     ),
-    // FIXME(#14407)
     ungated!(
         deprecated, Normal,
         template!(
@@ -229,78 +302,86 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
             List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
             NameValueStr: "reason"
         ),
+        // This has special duplicate handling in E0550 to handle duplicates with rustc_deprecated
+        DuplicatesOk
     ),
 
     // Crate properties:
-    ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")),
-    ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")),
-    ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")),
+    ungated!(crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing),
+    ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), FutureWarnFollowing),
+    // crate_id is deprecated
+    ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing),
 
     // ABI, linking, symbols, and FFI
     ungated!(
         link, Normal,
         template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
+        DuplicatesOk,
     ),
-    ungated!(link_name, Normal, template!(NameValueStr: "name")),
-    ungated!(no_link, Normal, template!(Word)),
-    ungated!(repr, Normal, template!(List: "C")),
-    ungated!(export_name, Normal, template!(NameValueStr: "name")),
-    ungated!(link_section, Normal, template!(NameValueStr: "name")),
-    ungated!(no_mangle, Normal, template!(Word)),
-    ungated!(used, Normal, template!(Word)),
+    ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
+    ungated!(no_link, Normal, template!(Word), WarnFollowing),
+    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
+    ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
+    ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
+    ungated!(no_mangle, Normal, template!(Word), WarnFollowing),
+    ungated!(used, Normal, template!(Word), WarnFollowing),
 
     // Limits:
-    ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")),
-    ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")),
+    ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
+    ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
     gated!(
-        const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit,
-        experimental!(const_eval_limit)
+        const_eval_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
+        const_eval_limit, experimental!(const_eval_limit)
     ),
     gated!(
-        move_size_limit, CrateLevel, template!(NameValueStr: "N"), large_assignments,
-        experimental!(move_size_limit)
+        move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
+        large_assignments, experimental!(move_size_limit)
     ),
 
     // Entry point:
-    ungated!(main, Normal, template!(Word)),
-    ungated!(start, Normal, template!(Word)),
-    ungated!(no_start, CrateLevel, template!(Word)),
-    ungated!(no_main, CrateLevel, template!(Word)),
+    ungated!(main, Normal, template!(Word), WarnFollowing),
+    ungated!(start, Normal, template!(Word), WarnFollowing),
+    ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
+    ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
 
     // Modules, prelude, and resolution:
-    ungated!(path, Normal, template!(NameValueStr: "file")),
-    ungated!(no_std, CrateLevel, template!(Word)),
-    ungated!(no_implicit_prelude, Normal, template!(Word)),
-    ungated!(non_exhaustive, Normal, template!(Word)),
+    ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing),
+    ungated!(no_std, CrateLevel, template!(Word), WarnFollowing),
+    ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing),
+    ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing),
 
     // Runtime
-    ungated!(windows_subsystem, Normal, template!(NameValueStr: "windows|console")),
-    ungated!(panic_handler, Normal, template!(Word)), // RFC 2070
+    ungated!(
+        windows_subsystem, Normal,
+        template!(NameValueStr: "windows|console"), FutureWarnFollowing
+    ),
+    ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
 
     // Code generation:
-    ungated!(inline, Normal, template!(Word, List: "always|never")),
-    ungated!(cold, Normal, template!(Word)),
-    ungated!(no_builtins, Normal, template!(Word)),
-    ungated!(target_feature, Normal, template!(List: r#"enable = "name""#)),
-    ungated!(track_caller, Normal, template!(Word)),
+    ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
+    ungated!(cold, Normal, template!(Word), WarnFollowing),
+    ungated!(no_builtins, Normal, template!(Word), WarnFollowing),
+    ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
+    ungated!(track_caller, Normal, template!(Word), WarnFollowing),
     gated!(
         no_sanitize, Normal,
-        template!(List: "address, memory, thread"),
+        template!(List: "address, memory, thread"), DuplicatesOk,
         experimental!(no_sanitize)
     ),
-    gated!(no_coverage, Normal, template!(Word), experimental!(no_coverage)),
+    gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)),
 
-    // FIXME: #14408 assume docs are used since rustdoc looks at them.
-    ungated!(doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string")),
+    ungated!(
+        doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
+    ),
 
     // ==========================================================================
     // Unstable attributes:
     // ==========================================================================
 
     // Linking:
-    gated!(naked, Normal, template!(Word), naked_functions, experimental!(naked)),
+    gated!(naked, Normal, template!(Word), WarnFollowing, naked_functions, experimental!(naked)),
     gated!(
-        link_ordinal, Normal, template!(List: "ordinal"), raw_dylib,
+        link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib,
         experimental!(link_ordinal)
     ),
 
@@ -309,6 +390,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         name: sym::plugin,
         type_: CrateLevel,
         template: template!(List: "name"),
+        duplicates: DuplicatesOk,
         gate: Gated(
             Stability::Deprecated(
                 "https://github.com/rust-lang/rust/pull/64675",
@@ -321,42 +403,52 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     },
 
     // Testing:
-    gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)),
+    gated!(allow_fail, Normal, template!(Word), WarnFollowing, experimental!(allow_fail)),
     gated!(
-        test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks,
+        test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks,
         "custom test frameworks are an unstable feature",
     ),
     // RFC #1268
-    gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
     gated!(
-        thread_local, Normal, template!(Word),
+        marker, Normal, template!(Word), WarnFollowing, marker_trait_attr, experimental!(marker)
+    ),
+    gated!(
+        thread_local, Normal, template!(Word), WarnFollowing,
         "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
     ),
-    gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)),
+    gated!(no_core, CrateLevel, template!(Word), WarnFollowing, experimental!(no_core)),
     // RFC 2412
     gated!(
-        optimize, Normal, template!(List: "size|speed"), optimize_attribute,
+        optimize, Normal, template!(List: "size|speed"), ErrorPreceding, optimize_attribute,
         experimental!(optimize),
     ),
     // RFC 2867
-    gated!(instruction_set, Normal, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
+    gated!(
+        instruction_set, Normal, template!(List: "set"), ErrorPreceding,
+        isa_attribute, experimental!(instruction_set)
+    ),
 
-    gated!(ffi_returns_twice, Normal, template!(Word), experimental!(ffi_returns_twice)),
-    gated!(ffi_pure, Normal, template!(Word), experimental!(ffi_pure)),
-    gated!(ffi_const, Normal, template!(Word), experimental!(ffi_const)),
     gated!(
-        register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
+        ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice)
+    ),
+    gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)),
+    gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)),
+    gated!(
+        register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), DuplicatesOk,
         experimental!(register_attr),
     ),
     gated!(
-        register_tool, CrateLevel, template!(List: "tool1, tool2, ..."),
+        register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk,
         experimental!(register_tool),
     ),
 
-    gated!(cmse_nonsecure_entry, Normal, template!(Word), experimental!(cmse_nonsecure_entry)),
+    gated!(
+        cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing,
+        experimental!(cmse_nonsecure_entry)
+    ),
     // RFC 2632
     gated!(
-        default_method_body_is_const, Normal, template!(Word), const_trait_impl,
+        default_method_body_is_const, Normal, template!(Word), WarnFollowing, const_trait_impl,
         "`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
         as `const`, which may be removed or renamed in the future."
     ),
@@ -365,34 +457,33 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes: Stability, deprecation, and unsafe:
     // ==========================================================================
 
-    ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")),
-    // FIXME(#14407) -- only looked at on-demand so we can't
-    // guarantee they'll have already been checked.
+    ungated!(feature, CrateLevel, template!(List: "name1, name1, ..."), DuplicatesOk),
+    // DuplicatesOk since it has its own validation
     ungated!(
         rustc_deprecated, Normal,
-        template!(List: r#"since = "version", reason = "...""#)
+        template!(List: r#"since = "version", reason = "...""#), DuplicatesOk // See E0550
+    ),
+    // DuplicatesOk since it has its own validation
+    ungated!(
+        stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk
     ),
-    // FIXME(#14407)
-    ungated!(stable, Normal, template!(List: r#"feature = "name", since = "version""#)),
-    // FIXME(#14407)
     ungated!(
         unstable, Normal,
-        template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+        template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
     ),
-    // FIXME(#14407)
-    ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#)),
-    // FIXME(#14407)
-    ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#)),
+    ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
+    ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
     gated!(
-        allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
+        allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
         "allow_internal_unstable side-steps feature gating and stability checks",
     ),
     gated!(
-        rustc_allow_const_fn_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
+        rustc_allow_const_fn_unstable, Normal,
+        template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
         "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
     ),
     gated!(
-        allow_internal_unsafe, Normal, template!(Word),
+        allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
         "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
 
@@ -400,9 +491,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes: Type system related:
     // ==========================================================================
 
-    gated!(fundamental, Normal, template!(Word), experimental!(fundamental)),
+    gated!(fundamental, Normal, template!(Word), WarnFollowing, experimental!(fundamental)),
     gated!(
-        may_dangle, Normal, template!(Word), dropck_eyepatch,
+        may_dangle, Normal, template!(Word), WarnFollowing, dropck_eyepatch,
         "`may_dangle` has unstable semantics and may be removed in the future",
     ),
 
@@ -410,26 +501,32 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes: Runtime related:
     // ==========================================================================
 
-    rustc_attr!(rustc_allocator, Normal, template!(Word), IMPL_DETAIL),
-    rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), IMPL_DETAIL),
-    gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)),
+    rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+    rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+    gated!(
+        alloc_error_handler, Normal, template!(Word), WarnFollowing,
+        experimental!(alloc_error_handler)
+    ),
     gated!(
-        default_lib_allocator, Normal, template!(Word), allocator_internals,
+        default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
         experimental!(default_lib_allocator),
     ),
     gated!(
-        needs_allocator, Normal, template!(Word), allocator_internals,
+        needs_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
         experimental!(needs_allocator),
     ),
-    gated!(panic_runtime, Normal, template!(Word), experimental!(panic_runtime)),
-    gated!(needs_panic_runtime, Normal, template!(Word), experimental!(needs_panic_runtime)),
+    gated!(panic_runtime, Normal, template!(Word), WarnFollowing, experimental!(panic_runtime)),
     gated!(
-        compiler_builtins, Normal, template!(Word),
+        needs_panic_runtime, Normal, template!(Word), WarnFollowing,
+        experimental!(needs_panic_runtime)
+    ),
+    gated!(
+        compiler_builtins, Normal, template!(Word), WarnFollowing,
         "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
         which contains compiler-rt intrinsics and will never be stable",
     ),
     gated!(
-        profiler_runtime, Normal, template!(Word),
+        profiler_runtime, Normal, template!(Word), WarnFollowing,
         "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
         which contains the profiler runtime and will never be stable",
     ),
@@ -439,10 +536,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     gated!(
-        linkage, Normal, template!(NameValueStr: "external|internal|..."),
+        linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding,
         "the `linkage` attribute is experimental and not portable across platforms",
     ),
-    rustc_attr!(rustc_std_internal_symbol, Normal, template!(Word), INTERNAL_UNSTABLE),
+    rustc_attr!(
+        rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+    ),
 
     // ==========================================================================
     // Internal attributes, Macro related:
@@ -450,13 +549,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     rustc_attr!(
         rustc_builtin_macro, Normal,
-        template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
+        template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
         IMPL_DETAIL,
     ),
-    rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
+    rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
     rustc_attr!(
         rustc_macro_transparency, Normal,
-        template!(NameValueStr: "transparent|semitransparent|opaque"),
+        template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing,
         "used internally for testing macro hygiene",
     ),
 
@@ -470,39 +569,49 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
             List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
             NameValueStr: "message"
         ),
+        ErrorFollowing,
         INTERNAL_UNSTABLE
     ),
     // Enumerates "identity-like" conversion methods to suggest on type mismatch.
-    rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE),
+    rustc_attr!(
+        rustc_conversion_suggestion, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+    ),
     // Prevents field reads in the marked trait or method to be considered
     // during dead code analysis.
-    rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE),
+    rustc_attr!(
+        rustc_trivial_field_reads, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+    ),
 
     // ==========================================================================
     // Internal attributes, Const related:
     // ==========================================================================
 
-    rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL),
-    rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE),
+    rustc_attr!(rustc_promotable, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+    rustc_attr!(
+        rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
+        INTERNAL_UNSTABLE
+    ),
     // Do not const-check this function's body. It will always get replaced during CTFE.
-    rustc_attr!(rustc_do_not_const_check, Normal, template!(Word), INTERNAL_UNSTABLE),
+    rustc_attr!(
+        rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+    ),
 
     // ==========================================================================
     // Internal attributes, Layout related:
     // ==========================================================================
 
     rustc_attr!(
-        rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"),
+        rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
         "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
         niche optimizations in libcore and will never be stable",
     ),
     rustc_attr!(
-        rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"),
+        rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
         "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
         niche optimizations in libcore and will never be stable",
     ),
     rustc_attr!(
-        rustc_nonnull_optimization_guaranteed, Normal, template!(Word),
+        rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
         niche optimizations in libcore and will never be stable",
     ),
@@ -511,13 +620,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes, Misc:
     // ==========================================================================
     gated!(
-        lang, Normal, template!(NameValueStr: "name"), lang_items,
+        lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
         "language items are subject to change",
     ),
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
         type_: Normal,
         template: template!(NameValueStr: "name"),
+        duplicates: ErrorFollowing,
         gate: Gated(
             Stability::Unstable,
             sym::rustc_attrs,
@@ -527,41 +637,43 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     },
     gated!(
         // Used in resolve:
-        prelude_import, Normal, template!(Word),
+        prelude_import, Normal, template!(Word), WarnFollowing,
         "`#[prelude_import]` is for use by rustc only",
     ),
     gated!(
-        rustc_paren_sugar, Normal, template!(Word), unboxed_closures,
+        rustc_paren_sugar, Normal, template!(Word), WarnFollowing, unboxed_closures,
         "unboxed_closures are still evolving",
     ),
     rustc_attr!(
-        rustc_inherit_overflow_checks, Normal, template!(Word),
+        rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
         overflow checking behavior of several libcore functions that are inlined \
         across crates and will never be stable",
     ),
-    rustc_attr!(rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"),
-                "the `#[rustc_reservation_impl]` attribute is internally used \
-                 for reserving for `for<T> From<!> for T` impl"
+    rustc_attr!(
+        rustc_reservation_impl, Normal,
+        template!(NameValueStr: "reservation message"), ErrorFollowing,
+        "the `#[rustc_reservation_impl]` attribute is internally used \
+         for reserving for `for<T> From<!> for T` impl"
     ),
     rustc_attr!(
-        rustc_test_marker, Normal, template!(Word),
+        rustc_test_marker, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_test_marker]` attribute is used internally to track tests",
     ),
     rustc_attr!(
-        rustc_unsafe_specialization_marker, Normal, template!(Word),
+        rustc_unsafe_specialization_marker, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
     ),
     rustc_attr!(
-        rustc_specialization_trait, Normal, template!(Word),
+        rustc_specialization_trait, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_specialization_trait]` attribute is used to check specializations"
     ),
     rustc_attr!(
-        rustc_main, Normal, template!(Word),
+        rustc_main, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_main]` attribute is used internally to specify test entry point function",
     ),
     rustc_attr!(
-        rustc_skip_array_during_method_dispatch, Normal, template!(Word),
+        rustc_skip_array_during_method_dispatch, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
         from method dispatch when the receiver is an array, for compatibility in editions < 2021."
     ),
@@ -570,48 +682,53 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes, Testing:
     // ==========================================================================
 
-    rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
-    rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
+    rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
+    rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
     rustc_attr!(
         TEST, rustc_error, Normal,
-        template!(Word, List: "delay_span_bug_from_inside_query")
+        template!(Word, List: "delay_span_bug_from_inside_query"), WarnFollowingWordOnly
+    ),
+    rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(
+        TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk
+    ),
+    rustc_attr!(
+        TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk
     ),
-    rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode")),
-    rustc_attr!(TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode")),
     rustc_attr!(
         TEST, rustc_clean, Normal,
         template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
+        DuplicatesOk,
     ),
     rustc_attr!(
         TEST, rustc_partition_reused, Normal,
-        template!(List: r#"cfg = "...", module = "...""#),
+        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk,
     ),
     rustc_attr!(
         TEST, rustc_partition_codegened, Normal,
-        template!(List: r#"cfg = "...", module = "...""#),
+        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk,
     ),
     rustc_attr!(
         TEST, rustc_expected_cgu_reuse, Normal,
-        template!(List: r#"cfg = "...", module = "...", kind = "...""#),
-    ),
-    rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_def_path, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ...")),
-    rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word)),
-    rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
+        template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
+    ),
+    rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
+    rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk),
     gated!(
-        omit_gdb_pretty_printer_section, Normal, template!(Word),
+        omit_gdb_pretty_printer_section, Normal, template!(Word), WarnFollowing,
         "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
     ),
 ];
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index b25aab21e49..bfc537cfae2 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -11,6 +11,7 @@
 //! even if it is stabilized or removed, *do not remove it*. Instead, move the
 //! symbol to the `accepted` or `removed` modules respectively.
 
+#![feature(derive_default_enum)]
 #![feature(once_cell)]
 
 mod accepted;
@@ -146,6 +147,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU3
 
 pub use accepted::ACCEPTED_FEATURES;
 pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES};
+pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
     deprecated_attributes, find_gated_cfg, is_builtin_attr_name, AttributeGate, AttributeTemplate,
     AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index 5091a7bccc5..f19ca497d8b 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -1,52 +1,52 @@
-/// This declares a list of types which can be allocated by `Arena`.
+/// This higher-order macro declares a list of types which can be allocated by `Arena`.
 ///
 /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]`,
 /// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro.
 #[macro_export]
 macro_rules! arena_types {
-    ($macro:path, $tcx:lifetime) => (
+    ($macro:path) => (
         $macro!([
             // HIR types
-            [] hir_krate: rustc_hir::Crate<$tcx>,
-            [] arm: rustc_hir::Arm<$tcx>,
-            [] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span),
+            [] hir_krate: rustc_hir::Crate<'tcx>,
+            [] arm: rustc_hir::Arm<'tcx>,
+            [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, Span),
             [] asm_template: rustc_ast::InlineAsmTemplatePiece,
             [] attribute: rustc_ast::Attribute,
-            [] block: rustc_hir::Block<$tcx>,
-            [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
-            [] body: rustc_hir::Body<$tcx>,
-            [] generic_arg: rustc_hir::GenericArg<$tcx>,
-            [] generic_args: rustc_hir::GenericArgs<$tcx>,
-            [] generic_bound: rustc_hir::GenericBound<$tcx>,
-            [] generic_param: rustc_hir::GenericParam<$tcx>,
-            [] expr: rustc_hir::Expr<$tcx>,
-            [] expr_field: rustc_hir::ExprField<$tcx>,
-            [] pat_field: rustc_hir::PatField<$tcx>,
-            [] fn_decl: rustc_hir::FnDecl<$tcx>,
-            [] foreign_item: rustc_hir::ForeignItem<$tcx>,
+            [] block: rustc_hir::Block<'tcx>,
+            [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
+            [] body: rustc_hir::Body<'tcx>,
+            [] generic_arg: rustc_hir::GenericArg<'tcx>,
+            [] generic_args: rustc_hir::GenericArgs<'tcx>,
+            [] generic_bound: rustc_hir::GenericBound<'tcx>,
+            [] generic_param: rustc_hir::GenericParam<'tcx>,
+            [] expr: rustc_hir::Expr<'tcx>,
+            [] expr_field: rustc_hir::ExprField<'tcx>,
+            [] pat_field: rustc_hir::PatField<'tcx>,
+            [] fn_decl: rustc_hir::FnDecl<'tcx>,
+            [] foreign_item: rustc_hir::ForeignItem<'tcx>,
             [] foreign_item_ref: rustc_hir::ForeignItemRef,
-            [] impl_item: rustc_hir::ImplItem<$tcx>,
+            [] impl_item: rustc_hir::ImplItem<'tcx>,
             [] impl_item_ref: rustc_hir::ImplItemRef,
-            [] item: rustc_hir::Item<$tcx>,
-            [] inline_asm: rustc_hir::InlineAsm<$tcx>,
-            [] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
-            [] local: rustc_hir::Local<$tcx>,
-            [] mod_: rustc_hir::Mod<$tcx>,
-            [] owner_info: rustc_hir::OwnerInfo<$tcx>,
-            [] param: rustc_hir::Param<$tcx>,
-            [] pat: rustc_hir::Pat<$tcx>,
-            [] path: rustc_hir::Path<$tcx>,
-            [] path_segment: rustc_hir::PathSegment<$tcx>,
-            [] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>,
-            [] qpath: rustc_hir::QPath<$tcx>,
-            [] stmt: rustc_hir::Stmt<$tcx>,
-            [] field_def: rustc_hir::FieldDef<$tcx>,
-            [] trait_item: rustc_hir::TraitItem<$tcx>,
+            [] item: rustc_hir::Item<'tcx>,
+            [] inline_asm: rustc_hir::InlineAsm<'tcx>,
+            [] llvm_inline_asm: rustc_hir::LlvmInlineAsm<'tcx>,
+            [] local: rustc_hir::Local<'tcx>,
+            [] mod_: rustc_hir::Mod<'tcx>,
+            [] owner_info: rustc_hir::OwnerInfo<'tcx>,
+            [] param: rustc_hir::Param<'tcx>,
+            [] pat: rustc_hir::Pat<'tcx>,
+            [] path: rustc_hir::Path<'tcx>,
+            [] path_segment: rustc_hir::PathSegment<'tcx>,
+            [] poly_trait_ref: rustc_hir::PolyTraitRef<'tcx>,
+            [] qpath: rustc_hir::QPath<'tcx>,
+            [] stmt: rustc_hir::Stmt<'tcx>,
+            [] field_def: rustc_hir::FieldDef<'tcx>,
+            [] trait_item: rustc_hir::TraitItem<'tcx>,
             [] trait_item_ref: rustc_hir::TraitItemRef,
-            [] ty: rustc_hir::Ty<$tcx>,
-            [] type_binding: rustc_hir::TypeBinding<$tcx>,
-            [] variant: rustc_hir::Variant<$tcx>,
-            [] where_predicate: rustc_hir::WherePredicate<$tcx>,
-        ], $tcx);
+            [] ty: rustc_hir::Ty<'tcx>,
+            [] type_binding: rustc_hir::TypeBinding<'tcx>,
+            [] variant: rustc_hir::Variant<'tcx>,
+            [] where_predicate: rustc_hir::WherePredicate<'tcx>,
+        ]);
     )
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a4db57bfc11..c67d3df3ded 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1821,8 +1821,6 @@ impl<'hir> QPath<'hir> {
 pub enum LocalSource {
     /// A `match _ { .. }`.
     Normal,
-    /// A desugared `for _ in _ { .. }` loop.
-    ForLoopDesugar,
     /// When lowering async functions, we create locals within the `async move` so that
     /// all parameters are dropped after the future is polled.
     ///
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index b1f78a83e74..b30076100bb 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -2,6 +2,7 @@ use crate::def::{CtorOf, DefKind, Res};
 use crate::def_id::DefId;
 use crate::hir::{self, HirId, PatKind};
 use rustc_data_structures::stable_set::FxHashSet;
+use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -143,4 +144,14 @@ impl hir::Pat<'_> {
         });
         result
     }
+
+    /// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
+    pub fn for_loop_some(&self) -> Option<&Self> {
+        if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
+            if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
+                return Some(pat_field.pat);
+            }
+        }
+        None
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index c25ec1356e2..85226e60bdb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -310,6 +310,34 @@ pub fn unexpected_hidden_region_diagnostic(
     err
 }
 
+/// Structurally compares two types, modulo any inference variables.
+///
+/// Returns `true` if two types are equal, or if one type is an inference variable compatible
+/// with the other type. A TyVar inference type is compatible with any type, and an IntVar or
+/// FloatVar inference type are compatible with themselves or their concrete types (Int and
+/// Float types, respectively). When comparing two ADTs, these rules apply recursively.
+pub fn same_type_modulo_infer(a: Ty<'tcx>, b: Ty<'ctx>) -> bool {
+    match (&a.kind(), &b.kind()) {
+        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
+            if did_a != did_b {
+                return false;
+            }
+
+            substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type_modulo_infer(a, b))
+        }
+        (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_)))
+        | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_) | &ty::Infer(ty::InferTy::IntVar(_)))
+        | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
+        | (
+            &ty::Infer(ty::InferTy::FloatVar(_)),
+            &ty::Float(_) | &ty::Infer(ty::InferTy::FloatVar(_)),
+        )
+        | (&ty::Infer(ty::InferTy::TyVar(_)), _)
+        | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
+        _ => a == b,
+    }
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
         debug!("report_region_errors(): {} errors to start", errors.len());
@@ -1667,11 +1695,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
             _ => exp_found,
         };
-        debug!("exp_found {:?} terr {:?}", exp_found, terr);
+        debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code);
         if let Some(exp_found) = exp_found {
-            self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
-            self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
-            self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+            let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
+                &cause.code
+            {
+                // Skip if the root_ty of the pattern is not the same as the expected_ty.
+                // If these types aren't equal then we've probably peeled off a layer of arrays.
+                same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected)
+            } else {
+                true
+            };
+
+            if should_suggest_fixes {
+                self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
+                self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
+                self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+            }
         }
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
@@ -1761,7 +1801,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             self.get_impl_future_output_ty(exp_found.expected),
             self.get_impl_future_output_ty(exp_found.found),
         ) {
-            (Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
+            (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match &cause.code {
                 ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
                     diag.multipart_suggestion(
                         "consider `await`ing on both `Future`s",
@@ -1793,7 +1833,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     diag.help("consider `await`ing on both `Future`s");
                 }
             },
-            (_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
+            (_, Some(ty)) if same_type_modulo_infer(exp_found.expected, ty) => {
                 diag.span_suggestion_verbose(
                     exp_span.shrink_to_hi(),
                     "consider `await`ing on the `Future`",
@@ -1801,7 +1841,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            (Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => match cause.code {
+            (Some(ty), _) if same_type_modulo_infer(ty, exp_found.found) => match cause.code {
                 ObligationCauseCode::Pattern { span: Some(span), .. }
                 | ObligationCauseCode::IfExpression(box IfExpressionCause { then: span, .. }) => {
                     diag.span_suggestion_verbose(
@@ -1851,7 +1891,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 .iter()
                 .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
                 .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
-                .find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
+                .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
             {
                 if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -1916,7 +1956,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                         | (_, ty::Infer(_))
                                         | (ty::Param(_), _)
                                         | (ty::Infer(_), _) => {}
-                                        _ if ty::TyS::same_type(exp_ty, found_ty) => {}
+                                        _ if same_type_modulo_infer(exp_ty, found_ty) => {}
                                         _ => show_suggestion = false,
                                     };
                                 }
@@ -2113,10 +2153,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         None
                     },
                     self.tcx.generics_of(owner.to_def_id()),
+                    hir.span(hir_id),
                 )
             });
+
+        let span = match generics {
+            // This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal
+            // for other diagnostics, so we need to recover it here.
+            Some((_, _, node)) if span.is_dummy() => node,
+            _ => span,
+        };
+
         let type_param_span = match (generics, bound_kind) {
-            (Some((_, ref generics)), GenericKind::Param(ref param)) => {
+            (Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
                 // Account for the case where `param` corresponds to `Self`,
                 // which doesn't have the expected type argument.
                 if !(generics.has_self && param.index == 0) {
@@ -2153,7 +2202,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
         let new_lt = generics
             .as_ref()
-            .and_then(|(parent_g, g)| {
+            .and_then(|(parent_g, g, _)| {
                 let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char));
                 let mut lts_names = g
                     .params
@@ -2175,7 +2224,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             .unwrap_or("'lt".to_string());
         let add_lt_sugg = generics
             .as_ref()
-            .and_then(|(_, g)| g.params.first())
+            .and_then(|(_, g, _)| g.params.first())
             .and_then(|param| param.def_id.as_local())
             .map(|def_id| {
                 (
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index e00003face9..a7e019a53ee 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -5,13 +5,12 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
 use rustc_middle::hir::map::Map;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
-use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -26,6 +25,7 @@ struct FindHirNodeVisitor<'a, 'tcx> {
     found_closure: Option<&'tcx Expr<'tcx>>,
     found_method_call: Option<&'tcx Expr<'tcx>>,
     found_exact_method_call: Option<&'tcx Expr<'tcx>>,
+    found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
     found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
 }
 
@@ -41,6 +41,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
             found_closure: None,
             found_method_call: None,
             found_exact_method_call: None,
+            found_for_loop_iter: None,
             found_use_diagnostic: None,
         }
     }
@@ -111,6 +112,15 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind {
+            if let Some(pat) = arm.pat.for_loop_some() {
+                if let Some(ty) = self.node_ty_contains_target(pat.hir_id) {
+                    self.found_for_loop_iter = Some(scrutinee);
+                    self.found_node_ty = Some(ty);
+                    return;
+                }
+            }
+        }
         if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
             if call_span == self.target_span
                 && Some(self.target)
@@ -643,10 +653,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(_)) => {
-                        "the element type for this iterator is not specified".to_string()
-                    }
-                    _ => format!("this needs {}", suffix),
+                    Some(_) => format!("this needs {}", suffix),
                 }
             } else {
                 format!("consider giving this pattern {}", suffix)
@@ -719,6 +726,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 //    = note: type must be known at this point
                 self.annotate_method_call(segment, e, &mut err);
             }
+        } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
+            err.span_label(
+                scrutinee.span,
+                "the element type for this iterator is not specified".to_string(),
+            );
         }
         // Instead of the following:
         // error[E0282]: type annotations needed
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index c6ccd9b60a9..2aaebed28ce 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -192,14 +192,16 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 ObligationCauseCode::MatchImpl(parent, ..) => &parent.code,
                 _ => &cause.code,
             };
-            if let ObligationCauseCode::ItemObligation(item_def_id) = *code {
+            if let (ObligationCauseCode::ItemObligation(item_def_id), None) =
+                (code, override_error_code)
+            {
                 // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
                 // lifetime as above, but called using a fully-qualified path to the method:
                 // `Foo::qux(bar)`.
                 let mut v = TraitObjectVisitor(FxHashSet::default());
                 v.visit_ty(param.param_ty);
                 if let Some((ident, self_ty)) =
-                    self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+                    self.get_impl_ident_and_self_ty_from_trait(*item_def_id, &v.0)
                 {
                     if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) {
                         override_error_code = Some(ident);
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b874947cc69..2fd01c2d595 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -95,9 +95,10 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
 /// This is used so that the region values inferred by HIR region solving are
 /// not exposed, and so that we can avoid doing work in HIR typeck that MIR
 /// typeck will also do.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Default)]
 pub enum RegionckMode {
     /// The default mode: report region errors, don't erase regions.
+    #[default]
     Solve,
     /// Erase the results of region after solving.
     Erase {
@@ -108,12 +109,6 @@ pub enum RegionckMode {
     },
 }
 
-impl Default for RegionckMode {
-    fn default() -> Self {
-        RegionckMode::Solve
-    }
-}
-
 impl RegionckMode {
     /// Indicates that the MIR borrowck will repeat these region
     /// checks, so we should ignore errors if NLL is (unconditionally)
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index d0f1ff649d0..e4b407e7c11 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -15,6 +15,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
+#![feature(derive_default_enum)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
 #![feature(let_else)]
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ab12c936710..24d4b050421 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,7 +20,9 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel};
+use rustc_target::spec::{
+    RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
+};
 
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
@@ -713,8 +715,8 @@ fn test_debugging_options_tracking_hash() {
     // This list is in alphabetical order.
     tracked!(allow_features, Some(vec![String::from("lang_items")]));
     tracked!(always_encode_mir, true);
-    tracked!(assume_incomplete_release, true);
     tracked!(asm_comments, true);
+    tracked!(assume_incomplete_release, true);
     tracked!(binary_dep_depinfo, true);
     tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
@@ -731,8 +733,8 @@ fn test_debugging_options_tracking_hash() {
     tracked!(human_readable_cgu_names, true);
     tracked!(inline_in_all_cgus, Some(true));
     tracked!(inline_mir, Some(true));
-    tracked!(inline_mir_threshold, Some(123));
     tracked!(inline_mir_hint_threshold, Some(123));
+    tracked!(inline_mir_threshold, Some(123));
     tracked!(instrument_coverage, Some(InstrumentCoverage::All));
     tracked!(instrument_mcount, true);
     tracked!(link_only, true);
@@ -764,7 +766,6 @@ fn test_debugging_options_tracking_hash() {
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
-    tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
     tracked!(report_delayed_bugs, true);
     tracked!(sanitizer, SanitizerSet::ADDRESS);
     tracked!(sanitizer_memory_track_origins, 2);
@@ -772,15 +773,17 @@ fn test_debugging_options_tracking_hash() {
     tracked!(saturating_float_casts, Some(true));
     tracked!(share_generics, Some(true));
     tracked!(show_span, Some(String::from("abc")));
+    tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
     tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
+    tracked!(stack_protector, StackProtector::All);
     tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
-    tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(trap_unreachable, Some(false));
     tracked!(treat_err_as_bug, NonZeroUsize::new(1));
+    tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
     tracked!(verify_llvm_ir, true);
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index ebe495872c4..e2ce7da0e84 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -79,6 +79,9 @@ enum LLVMRustAttribute {
   InaccessibleMemOnly = 27,
   SanitizeHWAddress = 28,
   WillReturn = 29,
+  StackProtectReq = 30,
+  StackProtectStrong = 31,
+  StackProtect = 32,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index e77d29bed71..bb6d42c1a9c 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -124,8 +124,18 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
 
 extern "C" LLVMValueRef
 LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
+  Module *Mod = unwrap(M);
   StringRef NameRef(Name, NameLen);
-  return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
+
+  // We don't use Module::getOrInsertGlobal because that returns a Constant*,
+  // which may either be the real GlobalVariable*, or a constant bitcast of it
+  // if our type doesn't match the original declaration. We always want the
+  // GlobalVariable* so we can access linkage, visibility, etc.
+  GlobalVariable *GV = Mod->getGlobalVariable(NameRef, true);
+  if (!GV)
+    GV = new GlobalVariable(*Mod, unwrap(Ty), false,
+                            GlobalValue::ExternalLinkage, nullptr, NameRef);
+  return wrap(GV);
 }
 
 extern "C" LLVMValueRef
@@ -203,6 +213,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::SanitizeHWAddress;
   case WillReturn:
     return Attribute::WillReturn;
+  case StackProtectReq:
+    return Attribute::StackProtectReq;
+  case StackProtectStrong:
+    return Attribute::StackProtectStrong;
+  case StackProtect:
+    return Attribute::StackProtect;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 7bc669f2b00..66e6b571beb 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -247,13 +247,24 @@ fn encodable_body(
                     })
                     .collect();
 
-                let result = quote! { ::rustc_serialize::Encoder::emit_enum_variant(
-                    __encoder,
-                   #variant_name,
-                   #variant_idx,
-                   #field_idx,
-                   |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
-                ) };
+                let result = if field_idx != 0 {
+                    quote! {
+                        ::rustc_serialize::Encoder::emit_enum_variant(
+                            __encoder,
+                            #variant_name,
+                            #variant_idx,
+                            #field_idx,
+                            |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
+                        )
+                    }
+                } else {
+                    quote! {
+                        ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
+                            __encoder,
+                            #variant_name,
+                        )
+                    }
+                };
                 variant_idx += 1;
                 result
             });
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 2bcc2a4f7cf..ee2e190e7cd 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -1,33 +1,33 @@
-/// This declares a list of types which can be allocated by `Arena`.
+/// This higher-order macro declares a list of types which can be allocated by `Arena`.
 ///
 /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type
 /// listed. These impls will appear in the implement_ty_decoder! macro.
 #[macro_export]
 macro_rules! arena_types {
-    ($macro:path, $tcx:lifetime) => (
+    ($macro:path) => (
         $macro!([
             [] layout: rustc_target::abi::Layout,
-            [] fn_abi: rustc_target::abi::call::FnAbi<$tcx, rustc_middle::ty::Ty<$tcx>>,
+            [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
             // AdtDef are interned and compared by address
             [] adt_def: rustc_middle::ty::AdtDef,
-            [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,
-            [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>,
-            [decode] mir: rustc_middle::mir::Body<$tcx>,
+            [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<'tcx>>,
+            [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<'tcx>>,
+            [decode] mir: rustc_middle::mir::Body<'tcx>,
             [] steal_promoted:
                 rustc_data_structures::steal::Steal<
                     rustc_index::vec::IndexVec<
                         rustc_middle::mir::Promoted,
-                        rustc_middle::mir::Body<$tcx>
+                        rustc_middle::mir::Body<'tcx>
                     >
                 >,
             [decode] promoted:
                 rustc_index::vec::IndexVec<
                     rustc_middle::mir::Promoted,
-                    rustc_middle::mir::Body<$tcx>
+                    rustc_middle::mir::Body<'tcx>
                 >,
-            [decode] typeck_results: rustc_middle::ty::TypeckResults<$tcx>,
+            [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
             [decode] borrowck_result:
-                rustc_middle::mir::BorrowCheckResult<$tcx>,
+                rustc_middle::mir::BorrowCheckResult<'tcx>,
             [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
@@ -78,14 +78,14 @@ macro_rules! arena_types {
             [] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
             [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
             [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
-            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>,
+            [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
             [] attribute: rustc_ast::Attribute,
             [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
             [] hir_id_set: rustc_hir::HirIdSet,
 
             // Interned types
-            [] tys: rustc_middle::ty::TyS<$tcx>,
-            [] predicates: rustc_middle::ty::PredicateInner<$tcx>,
+            [] tys: rustc_middle::ty::TyS<'tcx>,
+            [] predicates: rustc_middle::ty::PredicateInner<'tcx>,
 
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
             // since we need to allocate this type on both the `rustc_hir` arena
@@ -97,8 +97,8 @@ macro_rules! arena_types {
             [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
-        ], $tcx);
+        ]);
     )
 }
 
-arena_types!(rustc_arena::declare_arena, 'tcx);
+arena_types!(rustc_arena::declare_arena);
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 0894b805075..9ce9f65a490 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -30,6 +30,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(core_intrinsics)]
+#![feature(derive_default_enum)]
 #![feature(discriminant_kind)]
 #![feature(exhaustive_patterns)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 0e70d49ef49..881b14278e9 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -395,7 +395,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     match expn_data.kind {
         ExpnKind::Inlined
         | ExpnKind::Root
-        | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false,
+        | ExpnKind::Desugaring(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) => 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/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 597622b2ebf..8a5fc5feeb7 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -3,7 +3,7 @@
 
 pub use self::StabilityLevel::*;
 
-use crate::ty::{self, TyCtxt};
+use crate::ty::{self, DefIdTree, TyCtxt};
 use rustc_ast::NodeId;
 use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -90,6 +90,7 @@ pub fn report_unstable(
     feature: Symbol,
     reason: Option<Symbol>,
     issue: Option<NonZeroU32>,
+    suggestion: Option<(Span, String, String, Applicability)>,
     is_soft: bool,
     span: Span,
     soft_handler: impl FnOnce(&'static Lint, Span, &str),
@@ -116,8 +117,12 @@ pub fn report_unstable(
         if is_soft {
             soft_handler(SOFT_UNSTABLE, span, &msg)
         } else {
-            feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg)
-                .emit();
+            let mut err =
+                feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg);
+            if let Some((inner_types, ref msg, sugg, applicability)) = suggestion {
+                err.span_suggestion(inner_types, msg, sugg, applicability);
+            }
+            err.emit();
         }
     }
 }
@@ -271,7 +276,13 @@ pub enum EvalResult {
     Allow,
     /// We cannot use the item because it is unstable and we did not provide the
     /// corresponding feature gate.
-    Deny { feature: Symbol, reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
+    Deny {
+        feature: Symbol,
+        reason: Option<Symbol>,
+        issue: Option<NonZeroU32>,
+        suggestion: Option<(Span, String, String, Applicability)>,
+        is_soft: bool,
+    },
     /// The item does not have the `#[stable]` or `#[unstable]` marker assigned.
     Unmarked,
 }
@@ -292,6 +303,32 @@ fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
+// See issue #83250.
+fn suggestion_for_allocator_api(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+    span: Span,
+    feature: Symbol,
+) -> Option<(Span, String, String, Applicability)> {
+    if feature == sym::allocator_api {
+        if let Some(trait_) = tcx.parent(def_id) {
+            if tcx.is_diagnostic_item(sym::Vec, trait_) {
+                let sm = tcx.sess.parse_sess.source_map();
+                let inner_types = sm.span_extend_to_prev_char(span, '<', true);
+                if let Ok(snippet) = sm.span_to_snippet(inner_types) {
+                    return Some((
+                        inner_types,
+                        "consider wrapping the inner types in tuple".to_string(),
+                        format!("({})", snippet),
+                        Applicability::MaybeIncorrect,
+                    ));
+                }
+            }
+        }
+    }
+    None
+}
+
 impl<'tcx> TyCtxt<'tcx> {
     /// Evaluates the stability of an item.
     ///
@@ -406,7 +443,8 @@ impl<'tcx> TyCtxt<'tcx> {
                     }
                 }
 
-                EvalResult::Deny { feature, reason, issue, is_soft }
+                let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
+                EvalResult::Deny { feature, reason, issue, suggestion, is_soft }
             }
             Some(_) => {
                 // Stable APIs are always ok to call and deprecated APIs are
@@ -457,9 +495,16 @@ impl<'tcx> TyCtxt<'tcx> {
         };
         match self.eval_stability(def_id, id, span, method_span) {
             EvalResult::Allow => {}
-            EvalResult::Deny { feature, reason, issue, is_soft } => {
-                report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler)
-            }
+            EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
+                self.sess,
+                feature,
+                reason,
+                issue,
+                suggestion,
+                is_soft,
+                span,
+                soft_handler,
+            ),
             EvalResult::Unmarked => unmarked(span, def_id),
         }
     }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 245df636107..49071e7995b 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -23,6 +23,7 @@ use smallvec::SmallVec;
 
 use std::borrow::Cow;
 use std::fmt;
+use std::hash::{Hash, Hasher};
 use std::ops::Deref;
 
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
@@ -108,7 +109,7 @@ impl Deref for ObligationCause<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift)]
 pub struct ObligationCauseData<'tcx> {
     pub span: Span,
 
@@ -123,6 +124,14 @@ pub struct ObligationCauseData<'tcx> {
     pub code: ObligationCauseCode<'tcx>,
 }
 
+impl Hash for ObligationCauseData<'_> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.body_id.hash(state);
+        self.span.hash(state);
+        std::mem::discriminant(&self.code).hash(state);
+    }
+}
+
 impl<'tcx> ObligationCause<'tcx> {
     #[inline]
     pub fn new(
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 434008ecb1f..3f2b987b1e6 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -417,17 +417,17 @@ macro_rules! __impl_decoder_methods {
 macro_rules! impl_arena_allocatable_decoder {
     ([]$args:tt) => {};
     ([decode $(, $attrs:ident)*]
-     [[$name:ident: $ty:ty], $tcx:lifetime]) => {
-        impl<$tcx, D: TyDecoder<$tcx>> RefDecodable<$tcx, D> for $ty {
+     [$name:ident: $ty:ty]) => {
+        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty {
             #[inline]
-            fn decode(decoder: &mut D) -> Result<&$tcx Self, D::Error> {
+            fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
                 decode_arena_allocable(decoder)
             }
         }
 
-        impl<$tcx, D: TyDecoder<$tcx>> RefDecodable<$tcx, D> for [$ty] {
+        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] {
             #[inline]
-            fn decode(decoder: &mut D) -> Result<&$tcx Self, D::Error> {
+            fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
                 decode_arena_allocable_slice(decoder)
             }
         }
@@ -438,15 +438,15 @@ macro_rules! impl_arena_allocatable_decoder {
 }
 
 macro_rules! impl_arena_allocatable_decoders {
-    ([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
+    ([$($a:tt $name:ident: $ty:ty,)*]) => {
         $(
-            impl_arena_allocatable_decoder!($a [[$name: $ty], $tcx]);
+            impl_arena_allocatable_decoder!($a [$name: $ty]);
         )*
     }
 }
 
-rustc_hir::arena_types!(impl_arena_allocatable_decoders, 'tcx);
-arena_types!(impl_arena_allocatable_decoders, 'tcx);
+rustc_hir::arena_types!(impl_arena_allocatable_decoders);
+arena_types!(impl_arena_allocatable_decoders);
 
 #[macro_export]
 macro_rules! implement_ty_decoder {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5d9e7aaf72f..3846cf19d91 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -649,30 +649,74 @@ pub trait PrettyPrinter<'tcx>:
 
                     let mut first = true;
                     let mut is_sized = false;
+                    let mut is_future = false;
+                    let mut future_output_ty = None;
+
                     p!("impl");
                     for (predicate, _) in bounds {
                         let predicate = predicate.subst(self.tcx(), substs);
                         let bound_predicate = predicate.kind();
-                        if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() {
-                            let trait_ref = bound_predicate.rebind(pred.trait_ref);
-                            // Don't print +Sized, but rather +?Sized if absent.
-                            if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
-                                is_sized = true;
-                                continue;
+
+                        match bound_predicate.skip_binder() {
+                            ty::PredicateKind::Projection(projection_predicate) => {
+                                let Some(future_trait) = self.tcx().lang_items().future_trait() else { continue };
+                                let future_output_def_id =
+                                    self.tcx().associated_item_def_ids(future_trait)[0];
+
+                                if projection_predicate.projection_ty.item_def_id
+                                    == future_output_def_id
+                                {
+                                    // We don't account for multiple `Future::Output = Ty` contraints.
+                                    is_future = true;
+                                    future_output_ty = Some(projection_predicate.ty);
+                                }
                             }
+                            ty::PredicateKind::Trait(pred) => {
+                                let trait_ref = bound_predicate.rebind(pred.trait_ref);
+                                // Don't print +Sized, but rather +?Sized if absent.
+                                if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait()
+                                {
+                                    is_sized = true;
+                                    continue;
+                                }
 
-                            p!(
-                                write("{}", if first { " " } else { "+" }),
-                                print(trait_ref.print_only_trait_path())
-                            );
-                            first = false;
+                                if Some(trait_ref.def_id())
+                                    == self.tcx().lang_items().future_trait()
+                                {
+                                    is_future = true;
+                                    continue;
+                                }
+
+                                p!(
+                                    write("{}", if first { " " } else { " + " }),
+                                    print(trait_ref.print_only_trait_path())
+                                );
+
+                                first = false;
+                            }
+                            _ => {}
                         }
                     }
+
+                    if is_future {
+                        p!(write("{}Future", if first { " " } else { " + " }));
+                        first = false;
+
+                        if let Some(future_output_ty) = future_output_ty {
+                            // Don't print projection types, which we (unfortunately) see often
+                            // in the error outputs involving async blocks.
+                            if !matches!(future_output_ty.kind(), ty::Projection(_)) {
+                                p!("<Output = ", print(future_output_ty), ">");
+                            }
+                        }
+                    }
+
                     if !is_sized {
-                        p!(write("{}?Sized", if first { " " } else { "+" }));
+                        p!(write("{}?Sized", if first { " " } else { " + " }));
                     } else if first {
                         p!(" Sized");
                     }
+
                     Ok(self)
                 });
             }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 610f9bd8f82..7e054d1e17f 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1805,10 +1805,13 @@ impl<'tcx> TyS<'tcx> {
     pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
         match self.kind() {
             Adt(def, substs) => {
+                assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type");
                 let variant = def.non_enum_variant();
                 let f0_ty = variant.fields[0].ty(tcx, substs);
 
                 match f0_ty.kind() {
+                    // If the first field is an array, we assume it is the only field and its
+                    // elements are the SIMD components.
                     Array(f0_elem_ty, f0_len) => {
                         // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112
                         // The way we evaluate the `N` in `[T; N]` here only works since we use
@@ -1816,6 +1819,8 @@ impl<'tcx> TyS<'tcx> {
                         // if we use it in generic code. See the `simd-array-trait` ui test.
                         (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty)
                     }
+                    // Otherwise, the fields of this Adt are the SIMD components (and we assume they
+                    // all have the same type).
                     _ => (variant.fields.len() as u64, f0_ty),
                 }
             }
@@ -2258,10 +2263,11 @@ impl<'tcx> TyS<'tcx> {
 /// a miscompilation or unsoundness.
 ///
 /// When in doubt, use `VarianceDiagInfo::default()`
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
 pub enum VarianceDiagInfo<'tcx> {
     /// No additional information - this is the default.
     /// We will not add any additional information to error messages.
+    #[default]
     None,
     /// We switched our variance because a type occurs inside
     /// the generic argument of a mutable reference or pointer
@@ -2296,9 +2302,3 @@ impl<'tcx> VarianceDiagInfo<'tcx> {
         }
     }
 }
-
-impl<'tcx> Default for VarianceDiagInfo<'tcx> {
-    fn default() -> Self {
-        Self::None
-    }
-}
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 6320d5d4749..e3a05e01ea8 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1606,13 +1606,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // encounter a candidate where the test is not relevant; at
         // that point, we stop sorting.
         while let Some(candidate) = candidates.first_mut() {
-            if let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) {
-                let (candidate, rest) = candidates.split_first_mut().unwrap();
-                target_candidates[idx].push(candidate);
-                candidates = rest;
-            } else {
+            let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) else {
                 break;
-            }
+            };
+            let (candidate, rest) = candidates.split_first_mut().unwrap();
+            target_candidates[idx].push(candidate);
+            candidates = rest;
         }
         // at least the first candidate ought to be tested
         assert!(total_candidate_count > candidates.len());
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 4108ad50470..cb94e759972 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -966,59 +966,58 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 DropKind::Value,
             );
 
-            if let Some(arg) = arg_opt {
-                let pat = match tcx.hir().get(arg.pat.hir_id) {
-                    Node::Pat(pat) | Node::Binding(pat) => pat,
-                    node => bug!("pattern became {:?}", node),
-                };
-                let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
-                let original_source_scope = self.source_scope;
-                let span = pattern.span;
-                self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
-                match *pattern.kind {
-                    // Don't introduce extra copies for simple bindings
-                    PatKind::Binding {
-                        mutability,
-                        var,
-                        mode: BindingMode::ByValue,
-                        subpattern: None,
-                        ..
-                    } => {
-                        self.local_decls[local].mutability = mutability;
-                        self.local_decls[local].source_info.scope = self.source_scope;
-                        self.local_decls[local].local_info = if let Some(kind) = self_binding {
-                            Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
-                                BindingForm::ImplicitSelf(*kind),
-                            ))))
-                        } else {
-                            let binding_mode = ty::BindingMode::BindByValue(mutability);
-                            Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                                VarBindingForm {
-                                    binding_mode,
-                                    opt_ty_info,
-                                    opt_match_place: Some((Some(place), span)),
-                                    pat_span: span,
-                                },
-                            )))))
-                        };
-                        self.var_indices.insert(var, LocalsForNode::One(local));
-                    }
-                    _ => {
-                        scope = self.declare_bindings(
-                            scope,
-                            expr.span,
-                            &pattern,
-                            matches::ArmHasGuard(false),
-                            Some((Some(&place), span)),
-                        );
-                        let place_builder = PlaceBuilder::from(local);
-                        unpack!(
-                            block = self.place_into_pattern(block, pattern, place_builder, false)
-                        );
-                    }
+            let Some(arg) = arg_opt else {
+                continue;
+            };
+            let pat = match tcx.hir().get(arg.pat.hir_id) {
+                Node::Pat(pat) | Node::Binding(pat) => pat,
+                node => bug!("pattern became {:?}", node),
+            };
+            let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
+            let original_source_scope = self.source_scope;
+            let span = pattern.span;
+            self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
+            match *pattern.kind {
+                // Don't introduce extra copies for simple bindings
+                PatKind::Binding {
+                    mutability,
+                    var,
+                    mode: BindingMode::ByValue,
+                    subpattern: None,
+                    ..
+                } => {
+                    self.local_decls[local].mutability = mutability;
+                    self.local_decls[local].source_info.scope = self.source_scope;
+                    self.local_decls[local].local_info = if let Some(kind) = self_binding {
+                        Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
+                            BindingForm::ImplicitSelf(*kind),
+                        ))))
+                    } else {
+                        let binding_mode = ty::BindingMode::BindByValue(mutability);
+                        Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                            VarBindingForm {
+                                binding_mode,
+                                opt_ty_info,
+                                opt_match_place: Some((Some(place), span)),
+                                pat_span: span,
+                            },
+                        )))))
+                    };
+                    self.var_indices.insert(var, LocalsForNode::One(local));
+                }
+                _ => {
+                    scope = self.declare_bindings(
+                        scope,
+                        expr.span,
+                        &pattern,
+                        matches::ArmHasGuard(false),
+                        Some((Some(&place), span)),
+                    );
+                    let place_builder = PlaceBuilder::from(local);
+                    unpack!(block = self.place_into_pattern(block, pattern, place_builder, false));
                 }
-                self.source_scope = original_source_scope;
             }
+            self.source_scope = original_source_scope;
         }
 
         // Enter the argument pattern bindings source scope, if it exists.
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 0e82b187201..7940bd1f33d 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -256,23 +256,22 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             }
             PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => {
                 if self.inside_adt {
-                    if let ty::Ref(_, ty, _) = ty.kind() {
-                        match borrow_kind {
-                            BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
-                                if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
-                                    self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
-                                }
-                            }
-                            BorrowKind::Mut { .. } => {
-                                self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
-                            }
-                        }
-                    } else {
+                    let ty::Ref(_, ty, _) = ty.kind() else {
                         span_bug!(
                             pat.span,
                             "BindingMode::ByRef in pattern, but found non-reference type {}",
                             ty
                         );
+                    };
+                    match borrow_kind {
+                        BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
+                            if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
+                                self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
+                            }
+                        }
+                        BorrowKind::Mut { .. } => {
+                            self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
+                        }
                     }
                 }
                 visit::walk_pat(self, pat);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index e28fd2c5081..d74c53fae53 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -74,19 +74,16 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
 
         let (msg, sp) = match loc.source {
             hir::LocalSource::Normal => ("local binding", Some(loc.span)),
-            hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
             hir::LocalSource::AsyncFn => ("async fn binding", None),
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
             hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
-        self.check_patterns(&loc.pat, Irrefutable);
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
         intravisit::walk_param(self, param);
         self.check_irrefutable(&param.pat, "function argument", None);
-        self.check_patterns(&param.pat, Irrefutable);
     }
 }
 
@@ -161,12 +158,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
     fn check_match(
         &mut self,
         scrut: &hir::Expr<'_>,
-        arms: &'tcx [hir::Arm<'tcx>],
+        hir_arms: &'tcx [hir::Arm<'tcx>],
         source: hir::MatchSource,
     ) {
         let mut cx = self.new_cx(scrut.hir_id);
 
-        for arm in arms {
+        for arm in hir_arms {
             // Check the arm for some things unrelated to exhaustiveness.
             self.check_patterns(&arm.pat, Refutable);
             if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
@@ -178,7 +175,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
 
         let mut have_errors = false;
 
-        let arms: Vec<_> = arms
+        let arms: Vec<_> = hir_arms
             .iter()
             .map(|hir::Arm { pat, guard, .. }| MatchArm {
                 pat: self.lower_pattern(&mut cx, pat, &mut have_errors),
@@ -196,6 +193,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
 
         match source {
+            // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
+            // when the iterator is an uninhabited type. unreachable_code will trigger instead.
+            hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
             hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
                 report_arm_reachability(&cx, &report)
             }
@@ -208,7 +208,13 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let is_empty_match = arms.is_empty();
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
-            non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+            if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
+                // the for loop pattern is not irrefutable
+                let pat = hir_arms[1].pat.for_loop_some().unwrap();
+                self.check_irrefutable(pat, "`for` loop binding", None);
+            } else {
+                non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+            }
         }
     }
 
@@ -225,6 +231,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let witnesses = report.non_exhaustiveness_witnesses;
         if witnesses.is_empty() {
             // The pattern is irrefutable.
+            self.check_patterns(pat, Irrefutable);
             return;
         }
 
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 91dddc6cd55..2585701f60c 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -4,17 +4,18 @@
 
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
+use rustc_middle::mir::visit::{MirVisitable, Visitor};
 use rustc_middle::mir::{self, Body, Location};
 use rustc_middle::ty::{self, TyCtxt};
 
-use crate::drop_flag_effects;
 use crate::drop_flag_effects_for_function_entry;
 use crate::drop_flag_effects_for_location;
 use crate::elaborate_drops::DropFlagState;
 use crate::framework::SwitchIntEdgeEffects;
-use crate::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
+use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
 use crate::on_lookup_result_bits;
 use crate::MoveDataParamEnv;
+use crate::{drop_flag_effects, on_all_children_bits};
 use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
 
 mod borrowed_locals;
@@ -307,22 +308,45 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
-        _statement: &mir::Statement<'tcx>,
+        statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
+        });
+
+        if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+            return;
+        }
+
+        // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
+        for_each_mut_borrow(statement, location, |place| {
+            let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { return };
+            on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+                trans.gen(child);
+            })
         })
     }
 
     fn terminator_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
+        terminator: &mir::Terminator<'tcx>,
         location: Location,
     ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
+        });
+
+        if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+            return;
+        }
+
+        for_each_mut_borrow(terminator, location, |place| {
+            let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { return };
+            on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+                trans.gen(child);
+            })
         })
     }
 
@@ -427,7 +451,10 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
-        })
+        });
+
+        // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
+        // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
     }
 
     fn terminator_effect(
@@ -438,7 +465,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     ) {
         drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
-        })
+        });
     }
 
     fn call_return_effect(
@@ -704,3 +731,37 @@ fn switch_on_enum_discriminant(
         _ => None,
     }
 }
+
+struct OnMutBorrow<F>(F);
+
+impl<F> Visitor<'_> for OnMutBorrow<F>
+where
+    F: FnMut(&mir::Place<'_>),
+{
+    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) {
+        // FIXME: Does `&raw const foo` allow mutation? See #90413.
+        match rvalue {
+            mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
+            | mir::Rvalue::AddressOf(_, place) => (self.0)(place),
+
+            _ => {}
+        }
+
+        self.super_rvalue(rvalue, location)
+    }
+}
+
+/// Calls `f` for each mutable borrow or raw reference in the program.
+///
+/// This DOES NOT call `f` for a shared borrow of a type with interior mutability.  That's okay for
+/// initializedness, because we cannot move from an `UnsafeCell` (outside of `core::cell`), but
+/// other analyses will likely need to check for `!Freeze`.
+fn for_each_mut_borrow<'tcx>(
+    mir: &impl MirVisitable<'tcx>,
+    location: Location,
+    f: impl FnMut(&mir::Place<'_>),
+) {
+    let mut vis = OnMutBorrow(f);
+
+    mir.apply(location, &mut vis);
+}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 81328e09156..17e79a02360 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1121,7 +1121,7 @@ impl<'a> Parser<'a> {
         Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
     }
 
-    pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
+    pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
         if self.eat(&token::Semi) {
             let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
             err.span_suggestion_short(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 3d29d305021..3669a4fce9c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1032,6 +1032,8 @@ impl<'a> Parser<'a> {
             [IdentLike(_), Punct('+' | '-')] |
             // 1e+2 | 1e-2
             [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
+            // 1.2e+ | 1.2e-
+            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
             // 1.2e+3 | 1.2e-3
             [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
                 // See the FIXME about `TokenCursor` above.
@@ -1241,7 +1243,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::Unsafe) {
             self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs)
         } else if self.check_inline_const(0) {
-            self.parse_const_block(lo.to(self.token.span))
+            self.parse_const_block(lo.to(self.token.span), false)
         } else if self.is_do_catch_block() {
             self.recover_do_catch(attrs)
         } else if self.is_try_block() {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e50b983ec62..9212aaa87d1 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1095,8 +1095,12 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses inline const expressions.
-    fn parse_const_block(&mut self, span: Span) -> PResult<'a, P<Expr>> {
-        self.sess.gated_spans.gate(sym::inline_const, span);
+    fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> {
+        if pat {
+            self.sess.gated_spans.gate(sym::inline_const_pat, span);
+        } else {
+            self.sess.gated_spans.gate(sym::inline_const, span);
+        }
         self.eat_keyword(kw::Const);
         let blk = self.parse_block()?;
         let anon_const = AnonConst {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index b03b5459981..bb3947bb47a 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -437,7 +437,7 @@ impl<'a> Parser<'a> {
             PatKind::Box(pat)
         } else if self.check_inline_const(0) {
             // Parse `const pat`
-            let const_expr = self.parse_const_block(lo.to(self.token.span))?;
+            let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
 
             if let Some(re) = self.parse_range_end() {
                 self.parse_pat_range_begin_with(const_expr, re)?
@@ -817,7 +817,7 @@ impl<'a> Parser<'a> {
             // Ensure the user doesn't receive unhelpful unexpected token errors
             self.bump();
             if self.is_pat_range_end_start(0) {
-                let _ = self.parse_pat_range_end();
+                let _ = self.parse_pat_range_end().map_err(|mut e| e.cancel());
             }
 
             self.error_inclusive_range_with_extra_equals(span_with_eq);
@@ -884,7 +884,7 @@ impl<'a> Parser<'a> {
 
     fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
         if self.check_inline_const(0) {
-            self.parse_const_block(self.token.span)
+            self.parse_const_block(self.token.span, true)
         } else if self.check_path() {
             let lo = self.token.span;
             let (qself, path) = if self.eat_lt() {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 6ff2259dc5b..2def57cf02a 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -9,9 +9,9 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
-use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -23,6 +23,7 @@ use rustc_session::lint::builtin::{
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use std::collections::hash_map::Entry;
 
 pub(crate) fn target_from_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -69,7 +70,7 @@ impl CheckAttrVisitor<'tcx> {
         let mut doc_aliases = FxHashMap::default();
         let mut is_valid = true;
         let mut specified_inline = None;
-        let mut seen = FxHashSet::default();
+        let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
             let attr_is_valid = match attr.name_or_empty() {
@@ -148,6 +149,8 @@ impl CheckAttrVisitor<'tcx> {
                 _ => {}
             }
 
+            let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
+
             if hir_id != CRATE_HIR_ID {
                 if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
                     attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
@@ -165,21 +168,37 @@ impl CheckAttrVisitor<'tcx> {
                 }
             }
 
-            // Duplicate attributes
-            match attr.name_or_empty() {
-                name @ sym::macro_use => {
-                    let args = attr.meta_item_list().unwrap_or_else(Vec::new);
-                    let args: Vec<_> = args.iter().map(|arg| arg.name_or_empty()).collect();
-                    if !seen.insert((name, args)) {
-                        self.tcx.struct_span_lint_hir(
-                            UNUSED_ATTRIBUTES,
-                            hir_id,
+            if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
+                check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
+            }
+
+            // Warn on useless empty attributes.
+            if matches!(
+                attr.name_or_empty(),
+                sym::macro_use
+                    | sym::allow
+                    | sym::warn
+                    | sym::deny
+                    | sym::forbid
+                    | sym::feature
+                    | sym::repr
+                    | sym::target_feature
+            ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+            {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("unused attribute")
+                        .span_suggestion(
                             attr.span,
-                            |lint| lint.build("unused attribute").emit(),
-                        );
-                    }
-                }
-                _ => {}
+                            "remove this attribute",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        )
+                        .note(&format!(
+                            "attribute `{}` with an empty list has no effect",
+                            attr.name_or_empty()
+                        ))
+                        .emit();
+                });
             }
         }
 
@@ -1990,3 +2009,77 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_attrs, ..*providers };
 }
+
+fn check_duplicates(
+    tcx: TyCtxt<'_>,
+    attr: &Attribute,
+    hir_id: HirId,
+    duplicates: AttributeDuplicates,
+    seen: &mut FxHashMap<Symbol, Span>,
+) {
+    use AttributeDuplicates::*;
+    if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
+        return;
+    }
+    match duplicates {
+        DuplicatesOk => {}
+        WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
+            match seen.entry(attr.name_or_empty()) {
+                Entry::Occupied(mut entry) => {
+                    let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
+                        let to_remove = entry.insert(attr.span);
+                        (to_remove, attr.span)
+                    } else {
+                        (attr.span, *entry.get())
+                    };
+                    tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| {
+                        let mut db = lint.build("unused attribute");
+                        db.span_note(other, "attribute also specified here").span_suggestion(
+                            this,
+                            "remove this attribute",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        );
+                        if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) {
+                            db.warn(
+                                "this was previously accepted by the compiler but is \
+                                 being phased out; it will become a hard error in \
+                                 a future release!",
+                            );
+                        }
+                        db.emit();
+                    });
+                }
+                Entry::Vacant(entry) => {
+                    entry.insert(attr.span);
+                }
+            }
+        }
+        ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
+            Entry::Occupied(mut entry) => {
+                let (this, other) = if matches!(duplicates, ErrorPreceding) {
+                    let to_remove = entry.insert(attr.span);
+                    (to_remove, attr.span)
+                } else {
+                    (attr.span, *entry.get())
+                };
+                tcx.sess
+                    .struct_span_err(
+                        this,
+                        &format!("multiple `{}` attributes", attr.name_or_empty()),
+                    )
+                    .span_note(other, "attribute also specified here")
+                    .span_suggestion(
+                        this,
+                        "remove this attribute",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(attr.span);
+            }
+        },
+    }
+}
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 1b992cdb0c9..b1295ba48cc 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -6,6 +6,7 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(thread_local_const_init)]
+#![feature(extern_types)]
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 9703f0c3d96..b08db39e245 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -18,6 +18,7 @@ use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
 use rustc_data_structures::sync::{Lock, LockGuard};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{DiagnosticBuilder, FatalError};
+use rustc_session::Session;
 use rustc_span::{Span, DUMMY_SP};
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
@@ -595,38 +596,86 @@ fn incremental_verify_ich<CTX, K, V: Debug>(
     debug!("END verify_ich({:?})", dep_node);
 
     if Some(new_hash) != old_hash {
-        let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
-            format!("`cargo clean -p {}` or `cargo clean`", crate_name)
-        } else {
-            "`cargo clean`".to_string()
-        };
+        incremental_verify_ich_cold(tcx.sess(), DebugArg::from(&dep_node), DebugArg::from(&result));
+    }
+}
 
-        // When we emit an error message and panic, we try to debug-print the `DepNode`
-        // and query result. Unforunately, this can cause us to run additional queries,
-        // which may result in another fingerprint mismatch while we're in the middle
-        // of processing this one. To avoid a double-panic (which kills the process
-        // before we can print out the query static), we print out a terse
-        // but 'safe' message if we detect a re-entrant call to this method.
-        thread_local! {
-            static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
-        };
+// This DebugArg business is largely a mirror of std::fmt::ArgumentV1, which is
+// currently not exposed publicly.
+//
+// The PR which added this attempted to use `&dyn Debug` instead, but that
+// showed statistically significant worse compiler performance. It's not
+// actually clear what the cause there was -- the code should be cold. If this
+// can be replaced with `&dyn Debug` with on perf impact, then it probably
+// should be.
+extern "C" {
+    type Opaque;
+}
 
-        let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+struct DebugArg<'a> {
+    value: &'a Opaque,
+    fmt: fn(&Opaque, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
+}
 
-        if old_in_panic {
-            tcx.sess().struct_err("internal compiler error: re-entrant incremental verify failure, suppressing message")
-                .emit();
-        } else {
-            tcx.sess().struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
+impl<'a, T> From<&'a T> for DebugArg<'a>
+where
+    T: std::fmt::Debug,
+{
+    fn from(value: &'a T) -> DebugArg<'a> {
+        DebugArg {
+            value: unsafe { std::mem::transmute(value) },
+            fmt: unsafe {
+                std::mem::transmute(<T as std::fmt::Debug>::fmt as fn(_, _) -> std::fmt::Result)
+            },
+        }
+    }
+}
+
+impl std::fmt::Debug for DebugArg<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        (self.fmt)(self.value, f)
+    }
+}
+
+// Note that this is marked #[cold] and intentionally takes the equivalent of
+// `dyn Debug` for its arguments, as we want to avoid generating a bunch of
+// different implementations for LLVM to chew on (and filling up the final
+// binary, too).
+#[cold]
+fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
+    let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
+        format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+    } else {
+        "`cargo clean`".to_string()
+    };
+
+    // When we emit an error message and panic, we try to debug-print the `DepNode`
+    // and query result. Unfortunately, this can cause us to run additional queries,
+    // which may result in another fingerprint mismatch while we're in the middle
+    // of processing this one. To avoid a double-panic (which kills the process
+    // before we can print out the query static), we print out a terse
+    // but 'safe' message if we detect a re-entrant call to this method.
+    thread_local! {
+        static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
+    };
+
+    let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+
+    if old_in_panic {
+        sess.struct_err(
+            "internal compiler error: re-entrant incremental verify failure, suppressing message",
+        )
+        .emit();
+    } else {
+        sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
                 .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
                 .note(&"Please follow the instructions below to create a bug report with the provided information")
                 .note(&"See <https://github.com/rust-lang/rust/issues/84970> for more information")
                 .emit();
-            panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
-        }
-
-        INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
+        panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
     }
+
+    INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
 }
 
 /// Ensure that either this query has all green inputs or been executed.
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index c46a18e5103..2e4cb4ff727 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -450,12 +450,24 @@ impl<'a> Resolver<'a> {
                 // let foo =...
                 //     ^^^ given this Span
                 // ------- get this Span to have an applicable suggestion
+
+                // edit:
+                // only do this if the const and usage of the non-constant value are on the same line
+                // the further the two are apart, the higher the chance of the suggestion being wrong
+                // also make sure that the pos for the suggestion is not 0 (ICE #90878)
+
                 let sp =
                     self.session.source_map().span_extend_to_prev_str(ident.span, current, true);
-                if sp.lo().0 == 0 {
+
+                let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32);
+
+                if sp.lo().0 == 0
+                    || pos_for_suggestion == 0
+                    || self.session.source_map().is_multiline(sp)
+                {
                     err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
                 } else {
-                    let sp = sp.with_lo(BytePos(sp.lo().0 - current.len() as u32));
+                    let sp = sp.with_lo(BytePos(pos_for_suggestion));
                     err.span_suggestion(
                         sp,
                         &format!("consider using `{}` instead of `{}`", sugg, current),
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4262c1e9051..bf4cece8bde 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1180,11 +1180,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         let mut reexport_error = None;
         let mut any_successful_reexport = false;
+        let mut crate_private_reexport = false;
         self.r.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
                 let vis = import.vis.get();
                 if !binding.vis.is_at_least(vis, &*this) {
                     reexport_error = Some((ns, binding));
+                    if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
+                        if binding_def_id.is_top_level_module() {
+                            crate_private_reexport = true;
+                        }
+                    }
                 } else {
                     any_successful_reexport = true;
                 }
@@ -1207,24 +1213,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     import.span,
                     &msg,
                 );
-            } else if ns == TypeNS {
-                struct_span_err!(
-                    self.r.session,
-                    import.span,
-                    E0365,
-                    "`{}` is private, and cannot be re-exported",
-                    ident
-                )
-                .span_label(import.span, format!("re-export of private `{}`", ident))
-                .note(&format!("consider declaring type or module `{}` with `pub`", ident))
-                .emit();
             } else {
-                let msg = format!("`{}` is private, and cannot be re-exported", ident);
-                let note_msg =
-                    format!("consider marking `{}` as `pub` in the imported module", ident,);
-                struct_span_err!(self.r.session, import.span, E0364, "{}", &msg)
-                    .span_note(import.span, &note_msg)
-                    .emit();
+                let error_msg = if crate_private_reexport {
+                    format!(
+                        "`{}` is only public within the crate, and cannot be re-exported outside",
+                        ident
+                    )
+                } else {
+                    format!("`{}` is private, and cannot be re-exported", ident)
+                };
+
+                if ns == TypeNS {
+                    let label_msg = if crate_private_reexport {
+                        format!("re-export of crate public `{}`", ident)
+                    } else {
+                        format!("re-export of private `{}`", ident)
+                    };
+
+                    struct_span_err!(self.r.session, import.span, E0365, "{}", error_msg)
+                        .span_label(import.span, label_msg)
+                        .note(&format!("consider declaring type or module `{}` with `pub`", ident))
+                        .emit();
+                } else {
+                    let note_msg =
+                        format!("consider marking `{}` as `pub` in the imported module", ident);
+                    struct_span_err!(self.r.session, import.span, E0364, "{}", error_msg)
+                        .span_note(import.span, &note_msg)
+                        .emit();
+                }
             }
         }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 31fd9b989e1..28dbce0471e 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1133,6 +1133,7 @@ impl<'a> Resolver<'a> {
                         feature,
                         reason,
                         issue,
+                        None,
                         is_soft,
                         span,
                         soft_handler,
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index e5369b4bbfd..df78e1bcbf6 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -589,6 +589,13 @@ impl<'a> crate::Encoder for Encoder<'a> {
         }
     }
 
+    fn emit_fieldless_enum_variant<const ID: usize>(
+        &mut self,
+        name: &str,
+    ) -> Result<(), Self::Error> {
+        escape_str(self.writer, name)
+    }
+
     fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
@@ -885,6 +892,13 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> {
         }
     }
 
+    fn emit_fieldless_enum_variant<const ID: usize>(
+        &mut self,
+        name: &str,
+    ) -> Result<(), Self::Error> {
+        escape_str(self.writer, name)
+    }
+
     fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index e32e4493726..96a2231b590 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -58,6 +58,20 @@ pub trait Encoder {
         f(self)
     }
 
+    // We put the field index in a const generic to allow the emit_usize to be
+    // compiled into a more efficient form. In practice, the variant index is
+    // known at compile-time, and that knowledge allows much more efficient
+    // codegen than we'd otherwise get. LLVM isn't always able to make the
+    // optimization that would otherwise be necessary here, likely due to the
+    // multiple levels of inlining and const-prop that are needed.
+    #[inline]
+    fn emit_fieldless_enum_variant<const ID: usize>(
+        &mut self,
+        _v_name: &str,
+    ) -> Result<(), Self::Error> {
+        self.emit_usize(ID)
+    }
+
     #[inline]
     fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
     where
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 3f0a6b0e2f6..ab3c122053c 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -335,9 +335,10 @@ impl Default for ErrorOutputType {
 }
 
 /// Parameter to control path trimming.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
 pub enum TrimmedDefPaths {
     /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
+    #[default]
     Never,
     /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
     Always,
@@ -345,12 +346,6 @@ pub enum TrimmedDefPaths {
     GoodPath,
 }
 
-impl Default for TrimmedDefPaths {
-    fn default() -> Self {
-        Self::Never
-    }
-}
-
 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
@@ -538,6 +533,7 @@ pub enum PrintRequest {
     TlsModels,
     TargetSpec,
     NativeStaticLibs,
+    StackProtectorStrategies,
 }
 
 #[derive(Copy, Clone)]
@@ -1110,8 +1106,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "print",
             "Compiler information to print on stdout",
             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
-             target-cpus|target-features|relocation-models|\
-             code-models|tls-models|target-spec-json|native-static-libs]",
+             target-cpus|target-features|relocation-models|code-models|\
+             tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
         ),
         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1527,6 +1523,7 @@ fn collect_print_requests(
         "code-models" => PrintRequest::CodeModels,
         "tls-models" => PrintRequest::TlsModels,
         "native-static-libs" => PrintRequest::NativeStaticLibs,
+        "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
         "target-spec-json" => {
             if dopts.unstable_options {
                 PrintRequest::TargetSpec
@@ -2494,7 +2491,9 @@ crate mod dep_tracking {
     use rustc_span::edition::Edition;
     use rustc_span::RealFileName;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
-    use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
+    use rustc_target::spec::{
+        RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+    };
     use std::collections::hash_map::DefaultHasher;
     use std::collections::BTreeMap;
     use std::hash::Hash;
@@ -2568,6 +2567,7 @@ crate mod dep_tracking {
         Edition,
         LinkerPluginLto,
         SplitDebuginfo,
+        StackProtector,
         SwitchWithOptPath,
         SymbolManglingVersion,
         SourceFileHashAlgorithm,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 6c86f86ecd9..399b616915e 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(crate_visibility_modifier)]
+#![feature(derive_default_enum)]
 #![feature(min_specialization)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index cba05f6aa59..a84e16b9dc3 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -5,7 +5,9 @@ use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
-use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
+use rustc_target::spec::{
+    RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+};
 
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::Edition;
@@ -385,6 +387,8 @@ mod desc {
     pub const parse_split_debuginfo: &str =
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
     pub const parse_gcc_ld: &str = "one of: no value, `lld`";
+    pub const parse_stack_protector: &str =
+        "one of (`none` (default), `basic`, `strong`, or `all`)";
 }
 
 mod parse {
@@ -917,6 +921,14 @@ mod parse {
         }
         true
     }
+
+    crate fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
+        match v.and_then(|s| StackProtector::from_str(s).ok()) {
+            Some(ssp) => *slot = ssp,
+            _ => return false,
+        }
+        true
+    }
 }
 
 options! {
@@ -1330,6 +1342,8 @@ options! {
         "exclude spans when debug-printing compiler state (default: no)"),
     src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
         "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
+    stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
+        "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
     split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 74b3cfa44c3..69494e6d9b3 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -27,7 +27,9 @@ use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, S
 use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
-use rustc_target::spec::{SanitizerSet, SplitDebuginfo, Target, TargetTriple, TlsModel};
+use rustc_target::spec::{
+    SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+};
 
 use std::cell::{self, RefCell};
 use std::env;
@@ -732,6 +734,14 @@ impl Session {
         self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
     }
 
+    pub fn stack_protector(&self) -> StackProtector {
+        if self.target.options.supports_stack_protector {
+            self.opts.debugging_opts.stack_protector
+        } else {
+            StackProtector::None
+        }
+    }
+
     pub fn target_can_use_split_dwarf(&self) -> bool {
         !self.target.is_like_windows && !self.target.is_like_osx
     }
@@ -1411,6 +1421,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             sess.err("`-Zsanitizer=cfi` requires `-Clto`");
         }
     }
+
+    if sess.opts.debugging_opts.stack_protector != StackProtector::None {
+        if !sess.target.options.supports_stack_protector {
+            sess.warn(&format!(
+                "`-Z stack-protector={}` is not supported for target {} and will be ignored",
+                sess.opts.debugging_opts.stack_protector, sess.opts.target_triple
+            ))
+        }
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 724d1904dc3..d590776676b 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1099,18 +1099,11 @@ pub enum DesugaringKind {
     OpaqueTy,
     Async,
     Await,
-    ForLoop(ForLoopLoc),
+    ForLoop,
     LetElse,
     WhileLoop,
 }
 
-/// A location in the desugaring of a `for` loop
-#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
-pub enum ForLoopLoc {
-    Head,
-    IntoIter,
-}
-
 impl DesugaringKind {
     /// The description wording should combine well with "desugaring of {}".
     pub fn descr(self) -> &'static str {
@@ -1121,7 +1114,7 @@ impl DesugaringKind {
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
-            DesugaringKind::ForLoop(_) => "`for` loop",
+            DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::LetElse => "`let...else`",
             DesugaringKind::WhileLoop => "`while` loop",
         }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index dfc64f37e4c..66c01140abc 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -41,7 +41,7 @@ pub mod edition;
 use edition::Edition;
 pub mod hygiene;
 use hygiene::Transparency;
-pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind};
+pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
 pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
 pub mod def_id;
 use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
@@ -1935,6 +1935,7 @@ pub struct Loc {
 #[derive(Debug)]
 pub struct SourceFileAndLine {
     pub sf: Lrc<SourceFile>,
+    /// Index of line, starting from 0.
     pub line: usize,
 }
 #[derive(Debug)]
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 74958c49849..7414d201f51 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -593,14 +593,19 @@ impl SourceMap {
     }
 
     pub fn span_to_margin(&self, sp: Span) -> Option<usize> {
-        match self.span_to_prev_source(sp) {
-            Err(_) => None,
-            Ok(source) => {
-                let last_line = source.rsplit_once('\n').unwrap_or(("", &source)).1;
+        Some(self.indentation_before(sp)?.len())
+    }
 
-                Some(last_line.len() - last_line.trim_start().len())
-            }
-        }
+    pub fn indentation_before(&self, sp: Span) -> Option<String> {
+        self.span_to_source(sp, |src, start_index, _| {
+            let before = &src[..start_index];
+            let last_line = before.rsplit_once('\n').map_or(before, |(_, last)| last);
+            Ok(last_line
+                .split_once(|c: char| !c.is_whitespace())
+                .map_or(last_line, |(indent, _)| indent)
+                .to_string())
+        })
+        .ok()
     }
 
     /// Returns the source snippet as `String` before the given `Span`.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9992b1f31fe..c34cf822765 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -269,7 +269,6 @@ symbols! {
         __D,
         __H,
         __S,
-        __next,
         __try_var,
         _args,
         _d,
@@ -308,6 +307,7 @@ symbols! {
         alloc_layout,
         alloc_zeroed,
         allocator,
+        allocator_api,
         allocator_internals,
         allow,
         allow_fail,
@@ -732,6 +732,7 @@ symbols! {
         inlateout,
         inline,
         inline_const,
+        inline_const_pat,
         inout,
         instruction_set,
         intel,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0771f998535..0d49c7f6ee8 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -712,6 +712,59 @@ impl ToJson for FramePointer {
     }
 }
 
+/// Controls use of stack canaries.
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
+pub enum StackProtector {
+    /// Disable stack canary generation.
+    None,
+
+    /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see
+    /// llvm/docs/LangRef.rst). This triggers stack canary generation in
+    /// functions which contain an array of a byte-sized type with more than
+    /// eight elements.
+    Basic,
+
+    /// On LLVM, mark all generated LLVM functions with the `sspstrong`
+    /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary
+    /// generation in functions which either contain an array, or which take
+    /// the address of a local variable.
+    Strong,
+
+    /// Generate stack canaries in all functions.
+    All,
+}
+
+impl StackProtector {
+    fn as_str(&self) -> &'static str {
+        match self {
+            StackProtector::None => "none",
+            StackProtector::Basic => "basic",
+            StackProtector::Strong => "strong",
+            StackProtector::All => "all",
+        }
+    }
+}
+
+impl FromStr for StackProtector {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<StackProtector, ()> {
+        Ok(match s {
+            "none" => StackProtector::None,
+            "basic" => StackProtector::Basic,
+            "strong" => StackProtector::Strong,
+            "all" => StackProtector::All,
+            _ => return Err(()),
+        })
+    }
+}
+
+impl fmt::Display for StackProtector {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
@@ -1360,6 +1413,10 @@ pub struct TargetOptions {
 
     /// Whether or not the DWARF `.debug_aranges` section should be generated.
     pub generate_arange_section: bool,
+
+    /// Whether the target supports stack canary checks. `true` by default,
+    /// since this is most common among tier 1 and tier 2 targets.
+    pub supports_stack_protector: bool,
 }
 
 impl Default for TargetOptions {
@@ -1466,6 +1523,7 @@ impl Default for TargetOptions {
             default_adjusted_cabi: None,
             c_enum_min_bits: 32,
             generate_arange_section: true,
+            supports_stack_protector: true,
         }
     }
 }
@@ -2052,6 +2110,7 @@ impl Target {
         key!(default_adjusted_cabi, Option<Abi>)?;
         key!(c_enum_min_bits, u64);
         key!(generate_arange_section, bool);
+        key!(supports_stack_protector, bool);
 
         if base.is_builtin {
             // This can cause unfortunate ICEs later down the line.
@@ -2292,6 +2351,7 @@ impl ToJson for Target {
         target_option_val!(supported_sanitizers);
         target_option_val!(c_enum_min_bits);
         target_option_val!(generate_arange_section);
+        target_option_val!(supports_stack_protector);
 
         if let Some(abi) = self.default_adjusted_cabi {
             d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 083262cf351..ba32a312910 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -44,6 +44,10 @@ pub fn target() -> Target {
             // produce kernel functions that call other kernel functions.
             // This behavior is not supported by PTX ISA.
             merge_functions: MergeFunctions::Disabled,
+
+            // The LLVM backend does not support stack canaries for this target
+            supports_stack_protector: false,
+
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 1a049e6ec64..1820e33b19b 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -14,6 +14,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
+#![feature(derive_default_enum)]
 #![feature(hash_drain_filter)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 1ff31ff04a2..a90140a9b50 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -27,7 +27,7 @@ use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
 
@@ -685,7 +685,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             &obligation.cause.code
         {
             parent_code.clone()
-        } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) =
+        } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
             span.ctxt().outer_expn_data().kind
         {
             Lrc::new(obligation.cause.code.clone())
@@ -765,8 +765,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // This if is to prevent a special edge-case
                     if matches!(
                         span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root
-                            | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
+                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
                     ) {
                         // We don't want a borrowing suggestion on the fields in structs,
                         // ```
@@ -1958,15 +1957,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     region, object_ty,
                 ));
             }
-            ObligationCauseCode::ItemObligation(item_def_id) => {
-                let item_name = tcx.def_path_str(item_def_id);
-                let msg = format!("required by `{}`", item_name);
-                let sp = tcx
-                    .hir()
-                    .span_if_local(item_def_id)
-                    .unwrap_or_else(|| tcx.def_span(item_def_id));
-                let sp = tcx.sess.source_map().guess_head_span(sp);
-                err.span_note(sp, &msg);
+            ObligationCauseCode::ItemObligation(_item_def_id) => {
+                // We hold the `DefId` of the item introducing the obligation, but displaying it
+                // doesn't add user usable information. It always point at an associated item.
             }
             ObligationCauseCode::BindingObligation(item_def_id, span) => {
                 let item_name = tcx.def_path_str(item_def_id);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 91671994c5a..4bc22d5d735 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -82,9 +82,14 @@ pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
 pub use rustc_infer::traits::*;
 
 /// Whether to skip the leak check, as part of a future compatibility warning step.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+///
+/// The "default" for skip-leak-check corresponds to the current
+/// behavior (do not skip the leak check) -- not the behavior we are
+/// transitioning into.
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
 pub enum SkipLeakCheck {
     Yes,
+    #[default]
     No,
 }
 
@@ -94,15 +99,6 @@ impl SkipLeakCheck {
     }
 }
 
-/// The "default" for skip-leak-check corresponds to the current
-/// behavior (do not skip the leak check) -- not the behavior we are
-/// transitioning into.
-impl Default for SkipLeakCheck {
-    fn default() -> Self {
-        SkipLeakCheck::No
-    }
-}
-
 /// The mode that trait queries run in.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum TraitQueryMode {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index ed49abbbedc..6d2323abba4 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -9,7 +9,9 @@ use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 
 use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
-pub use rustc_infer::traits::util::*;
+pub use rustc_infer::traits::{self, util::*};
+
+use std::iter;
 
 ///////////////////////////////////////////////////////////////////////////
 // `TraitAliasExpander` iterator
@@ -229,11 +231,16 @@ pub fn predicates_for_generics<'tcx>(
 ) -> impl Iterator<Item = PredicateObligation<'tcx>> {
     debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);
 
-    generic_bounds.predicates.into_iter().map(move |predicate| Obligation {
-        cause: cause.clone(),
-        recursion_depth,
-        param_env,
-        predicate,
+    iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| {
+        let cause = match cause.code {
+            traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new(
+                cause.span,
+                cause.body_id,
+                traits::BindingObligation(def_id, span),
+            ),
+            _ => cause.clone(),
+        };
+        Obligation { cause, recursion_depth, param_env, predicate }
     })
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index cb47ba9c360..2a66684e2a2 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -709,7 +709,12 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
         iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
             .map(|((pred, span), origin_def_id)| {
-                let cause = self.cause(traits::BindingObligation(origin_def_id, span));
+                let code = if span.is_dummy() {
+                    traits::MiscObligation
+                } else {
+                    traits::BindingObligation(origin_def_id, span)
+                };
+                let cause = self.cause(code);
                 traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
             })
             .filter(|pred| !pred.has_escaping_bound_vars())
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 5d22e300774..635ed938193 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -349,9 +349,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::FnPtr(sig) => (sig, None),
             ref t => {
                 let mut unit_variant = None;
+                let mut removal_span = call_expr.span;
                 if let ty::Adt(adt_def, ..) = t {
                     if adt_def.is_enum() {
                         if let hir::ExprKind::Call(expr, _) = call_expr.kind {
+                            removal_span =
+                                expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
                             unit_variant =
                                 self.tcx.sess.source_map().span_to_snippet(expr.span).ok();
                         }
@@ -379,14 +382,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
 
                 if let Some(ref path) = unit_variant {
-                    err.span_suggestion(
-                        call_expr.span,
+                    err.span_suggestion_verbose(
+                        removal_span,
                         &format!(
-                            "`{}` is a unit variant, you need to write it \
-                                 without the parentheses",
+                            "`{}` is a unit variant, you need to write it without the parentheses",
                             path
                         ),
-                        path.to_string(),
+                        String::new(),
                         Applicability::MachineApplicable,
                     );
                 }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index ef7c7096015..4d4662f73a9 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -210,12 +210,8 @@ fn compare_predicate_entailment<'tcx>(
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
     let param_env =
         ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
-    let param_env = traits::normalize_param_env_or_error(
-        tcx,
-        impl_m.def_id,
-        param_env,
-        normalize_cause.clone(),
-    );
+    let param_env =
+        traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
 
     tcx.infer_ctxt().enter(|infcx| {
         let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
@@ -226,12 +222,15 @@ fn compare_predicate_entailment<'tcx>(
         let mut selcx = traits::SelectionContext::new(&infcx);
 
         let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
-        for predicate in impl_m_own_bounds.predicates {
+        for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+            let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
             let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
+                traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
 
             inh.register_predicates(obligations);
-            inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
+            let mut cause = cause.clone();
+            cause.make_mut().span = span;
+            inh.register_predicate(traits::Obligation::new(cause, param_env, predicate));
         }
 
         // We now need to check that the signature of the impl method is
@@ -280,6 +279,12 @@ fn compare_predicate_entailment<'tcx>(
 
         let sub_result = infcx.at(&cause, param_env).sup(trait_fty, impl_fty).map(
             |InferOk { obligations, .. }| {
+                // FIXME: We'd want to keep more accurate spans than "the method signature" when
+                // processing the comparison between the trait and impl fn, but we sadly lose them
+                // and point at the whole signature when a trait bound or specific input or output
+                // type would be more appropriate. In other places we have a `Vec<Span>`
+                // corresponding to their `Vec<Predicate>`, but we don't have that here.
+                // Fixing this would improve the output of test `issue-83765.rs`.
                 inh.register_predicates(obligations);
             },
         );
@@ -1385,12 +1390,13 @@ pub fn check_type_bounds<'tcx>(
 
         let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
         let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
-        let mk_cause = |span| {
-            ObligationCause::new(
-                impl_ty_span,
-                impl_ty_hir_id,
-                ObligationCauseCode::BindingObligation(trait_ty.def_id, span),
-            )
+        let mk_cause = |span: Span| {
+            let code = if span.is_dummy() {
+                traits::MiscObligation
+            } else {
+                traits::BindingObligation(trait_ty.def_id, span)
+            };
+            ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
         };
 
         let obligations = tcx
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 9bbe5259147..ece2d7b4f37 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -199,7 +199,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return;
             }
 
-            let mut compatible_variants = expected_adt
+            // If the expression is of type () and it's the return expression of a block,
+            // we suggest adding a separate return expression instead.
+            // (To avoid things like suggesting `Ok(while .. { .. })`.)
+            if expr_ty.is_unit() {
+                if let Some(hir::Node::Block(&hir::Block {
+                    span: block_span, expr: Some(e), ..
+                })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
+                {
+                    if e.hir_id == expr.hir_id {
+                        if let Some(span) = expr.span.find_ancestor_inside(block_span) {
+                            let return_suggestions =
+                                if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) {
+                                    vec!["Ok(())".to_string()]
+                                } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did)
+                                {
+                                    vec!["None".to_string(), "Some(())".to_string()]
+                                } else {
+                                    return;
+                                };
+                            if let Some(indent) =
+                                self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
+                            {
+                                // Add a semicolon, except after `}`.
+                                let semicolon =
+                                    match self.tcx.sess.source_map().span_to_snippet(span) {
+                                        Ok(s) if s.ends_with('}') => "",
+                                        _ => ";",
+                                    };
+                                err.span_suggestions(
+                                    span.shrink_to_hi(),
+                                    "try adding an expression at the end of the block",
+                                    return_suggestions
+                                        .into_iter()
+                                        .map(|r| format!("{}\n{}{}", semicolon, indent, r)),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            return;
+                        }
+                    }
+                }
+            }
+
+            let compatible_variants: Vec<String> = expected_adt
                 .variants
                 .iter()
                 .filter(|variant| variant.fields.len() == 1)
@@ -220,19 +263,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         None
                     }
                 })
-                .peekable();
+                .collect();
 
-            if compatible_variants.peek().is_some() {
-                if let Ok(expr_text) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
-                    let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text));
-                    let msg = "try using a variant of the expected enum";
-                    err.span_suggestions(
-                        expr.span,
-                        msg,
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
+            if let [variant] = &compatible_variants[..] {
+                // Just a single matching variant.
+                err.multipart_suggestion(
+                    &format!("try wrapping the expression in `{}`", variant),
+                    vec![
+                        (expr.span.shrink_to_lo(), format!("{}(", variant)),
+                        (expr.span.shrink_to_hi(), ")".to_string()),
+                    ],
+                    Applicability::MaybeIncorrect,
+                );
+            } else if compatible_variants.len() > 1 {
+                // More than one matching variant.
+                err.multipart_suggestions(
+                    &format!(
+                        "try wrapping the expression in a variant of `{}`",
+                        self.tcx.def_path_str(expected_adt.did)
+                    ),
+                    compatible_variants.into_iter().map(|variant| {
+                        vec![
+                            (expr.span.shrink_to_lo(), format!("{}(", variant)),
+                            (expr.span.shrink_to_hi(), ")".to_string()),
+                        ]
+                    }),
+                    Applicability::MaybeIncorrect,
+                );
             }
         }
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index aae59eee991..142a0a8fc25 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -586,38 +586,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
-    /// type/region parameter was instantiated (`substs`), creates and registers suitable
-    /// trait/region obligations.
-    ///
-    /// For example, if there is a function:
-    ///
-    /// ```
-    /// fn foo<'a,T:'a>(...)
-    /// ```
-    ///
-    /// and a reference:
-    ///
-    /// ```
-    /// let f = foo;
-    /// ```
-    ///
-    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
-    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
-    pub fn add_obligations_for_parameters(
-        &self,
-        cause: traits::ObligationCause<'tcx>,
-        predicates: ty::InstantiatedPredicates<'tcx>,
-    ) {
-        assert!(!predicates.has_escaping_bound_vars());
-
-        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
-
-        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
-            self.register_predicate(obligation);
-        }
-    }
-
     // FIXME(arielb1): use this instead of field.ty everywhere
     // Only for fields! Returns <none> for methods>
     // Indifferent to privacy flags
@@ -1522,20 +1490,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Add all the obligations that are required, substituting and normalized appropriately.
     #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))]
-    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
-        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
+    crate fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+        let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
 
-        for (i, mut obligation) in traits::predicates_for_generics(
+        for obligation in traits::predicates_for_generics(
             traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
             self.param_env,
             bounds,
-        )
-        .enumerate()
-        {
-            // This makes the error point at the bound, but we want to point at the argument
-            if let Some(span) = spans.get(i) {
-                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
-            }
+        ) {
             self.register_predicate(obligation);
         }
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 7d9483201f6..a119a6838b8 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -509,10 +509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
 
             // Check bounds on type arguments used in the path.
-            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
-            let cause =
-                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
-            self.add_obligations_for_parameters(cause, bounds);
+            self.add_required_obligations(path_span, did, substs);
 
             Some((variant, ty))
         } else {
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index e7e4e72f6c1..dabfe92190b 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -120,7 +120,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // We won't add these if we encountered an illegal sized bound, so that we can use
         // a custom error in that case.
         if illegal_sized_bound.is_none() {
-            self.add_obligations(self.tcx.mk_fn_ptr(method_sig), all_substs, method_predicates);
+            self.add_obligations(
+                self.tcx.mk_fn_ptr(method_sig),
+                all_substs,
+                method_predicates,
+                pick.item.def_id,
+            );
         }
 
         // Create the final `MethodCallee`.
@@ -471,16 +476,23 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         fty: Ty<'tcx>,
         all_substs: SubstsRef<'tcx>,
         method_predicates: ty::InstantiatedPredicates<'tcx>,
+        def_id: DefId,
     ) {
         debug!(
-            "add_obligations: fty={:?} all_substs={:?} method_predicates={:?}",
-            fty, all_substs, method_predicates
+            "add_obligations: fty={:?} all_substs={:?} method_predicates={:?} def_id={:?}",
+            fty, all_substs, method_predicates, def_id
         );
 
-        self.add_obligations_for_parameters(
-            traits::ObligationCause::misc(self.span, self.body_id),
+        // FIXME: could replace with the following, but we already calculated `method_predicates`,
+        // so we just call `predicates_for_generics` directly to avoid redoing work.
+        // `self.add_required_obligations(self.span, def_id, &all_substs);`
+        for obligation in traits::predicates_for_generics(
+            traits::ObligationCause::new(self.span, self.body_id, traits::ItemObligation(def_id)),
+            self.param_env,
             method_predicates,
-        );
+        ) {
+            self.register_predicate(obligation);
+        }
 
         // this is a projection from a trait reference, so we have to
         // make sure that the trait reference inputs are well-formed.
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index f0f2470e80a..dbc1d4ec193 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -12,6 +12,7 @@ pub use self::CandidateSource::*;
 pub use self::MethodError::*;
 
 use crate::check::FnCtxt;
+use crate::ObligationCause;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -71,7 +72,8 @@ pub enum MethodError<'tcx> {
 #[derive(Debug)]
 pub struct NoMatchData<'tcx> {
     pub static_candidates: Vec<CandidateSource>,
-    pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+    pub unsatisfied_predicates:
+        Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
     pub out_of_scope_traits: Vec<DefId>,
     pub lev_candidate: Option<ty::AssocItem>,
     pub mode: probe::Mode,
@@ -80,7 +82,11 @@ pub struct NoMatchData<'tcx> {
 impl<'tcx> NoMatchData<'tcx> {
     pub fn new(
         static_candidates: Vec<CandidateSource>,
-        unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+        unsatisfied_predicates: Vec<(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )>,
         out_of_scope_traits: Vec<DefId>,
         lev_candidate: Option<ty::AssocItem>,
         mode: probe::Mode,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 95fe6c9b93c..9fd7e8c4daa 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -78,7 +78,8 @@ struct ProbeContext<'a, 'tcx> {
 
     /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
     /// for error reporting
-    unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+    unsatisfied_predicates:
+        Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
 
     is_suggestion: IsSuggestion,
 
@@ -1351,6 +1352,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         possibly_unsatisfied_predicates: &mut Vec<(
             ty::Predicate<'tcx>,
             Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
         )>,
         unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
     ) -> Option<PickResult<'tcx>>
@@ -1497,6 +1499,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         possibly_unsatisfied_predicates: &mut Vec<(
             ty::Predicate<'tcx>,
             Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
         )>,
     ) -> ProbeResult {
         debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
@@ -1508,8 +1511,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 .sup(probe.xform_self_ty, self_ty)
             {
                 Ok(InferOk { obligations, value: () }) => obligations,
-                Err(_) => {
-                    debug!("--> cannot relate self-types");
+                Err(err) => {
+                    debug!("--> cannot relate self-types {:?}", err);
                     return ProbeResult::NoMatch;
                 }
             };
@@ -1558,7 +1561,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         let o = self.resolve_vars_if_possible(o);
                         if !self.predicate_may_hold(&o) {
                             result = ProbeResult::NoMatch;
-                            possibly_unsatisfied_predicates.push((o.predicate, None));
+                            possibly_unsatisfied_predicates.push((
+                                o.predicate,
+                                None,
+                                Some(o.cause),
+                            ));
                         }
                     }
                 }
@@ -1604,8 +1611,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                             } else {
                                                 Some(predicate)
                                             };
-                                            possibly_unsatisfied_predicates
-                                                .push((nested_predicate, p));
+                                            possibly_unsatisfied_predicates.push((
+                                                nested_predicate,
+                                                p,
+                                                Some(obligation.cause.clone()),
+                                            ));
                                         }
                                     }
                                 }
@@ -1613,7 +1623,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                     // Some nested subobligation of this predicate
                                     // failed.
                                     let predicate = self.resolve_vars_if_possible(predicate);
-                                    possibly_unsatisfied_predicates.push((predicate, None));
+                                    possibly_unsatisfied_predicates.push((predicate, None, None));
                                 }
                             }
                             false
@@ -1632,7 +1642,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 let o = self.resolve_vars_if_possible(o);
                 if !self.predicate_may_hold(&o) {
                     result = ProbeResult::NoMatch;
-                    possibly_unsatisfied_predicates.push((o.predicate, None));
+                    possibly_unsatisfied_predicates.push((o.predicate, None, Some(o.cause)));
                 }
             }
 
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 6411c062fea..ca174ed5e84 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -17,7 +17,9 @@ use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{FulfillmentError, Obligation};
+use rustc_trait_selection::traits::{
+    FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
+};
 
 use std::cmp::Ordering;
 use std::iter;
@@ -702,27 +704,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
                                 (self_ty.kind(), parent_pred.kind().skip_binder())
                             {
-                                if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
-                                    let node = def.did.as_local().map(|def_id| {
+                                let node = match p.trait_ref.self_ty().kind() {
+                                    ty::Param(_) => {
+                                        // Account for `fn` items like in `issue-35677.rs` to
+                                        // suggest restricting its type params.
+                                        let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
+                                            hir_id: self.body_id,
+                                        });
+                                        Some(
+                                            self.tcx
+                                                .hir()
+                                                .get(self.tcx.hir().local_def_id_to_hir_id(did)),
+                                        )
+                                    }
+                                    ty::Adt(def, _) => def.did.as_local().map(|def_id| {
                                         self.tcx
                                             .hir()
                                             .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
-                                    });
-                                    if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
-                                        if let Some(g) = kind.generics() {
-                                            let key = match g.where_clause.predicates {
-                                                [.., pred] => (pred.span().shrink_to_hi(), false),
-                                                [] => (
-                                                    g.where_clause
-                                                        .span_for_predicates_or_empty_place(),
-                                                    true,
-                                                ),
-                                            };
-                                            type_params
-                                                .entry(key)
-                                                .or_insert_with(FxHashSet::default)
-                                                .insert(obligation.to_owned());
-                                        }
+                                    }),
+                                    _ => None,
+                                };
+                                if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
+                                    if let Some(g) = kind.generics() {
+                                        let key = match g.where_clause.predicates {
+                                            [.., pred] => (pred.span().shrink_to_hi(), false),
+                                            [] => (
+                                                g.where_clause.span_for_predicates_or_empty_place(),
+                                                true,
+                                            ),
+                                        };
+                                        type_params
+                                            .entry(key)
+                                            .or_insert_with(FxHashSet::default)
+                                            .insert(obligation.to_owned());
                                     }
                                 }
                             }
@@ -791,22 +805,109 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             _ => None,
                         }
                     };
+
+                    // Find all the requirements that come from a local `impl` block.
+                    let mut skip_list: FxHashSet<_> = Default::default();
+                    let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+                    for (data, p, parent_p) in unsatisfied_predicates
+                        .iter()
+                        .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+                        .filter_map(|(p, parent, c)| match c.code {
+                            ObligationCauseCode::ImplDerivedObligation(ref data) => {
+                                Some((data, p, parent))
+                            }
+                            _ => None,
+                        })
+                    {
+                        let parent_trait_ref = data.parent_trait_ref;
+                        let parent_def_id = parent_trait_ref.def_id();
+                        let path = parent_trait_ref.print_only_trait_path();
+                        let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+                        let mut candidates = vec![];
+                        self.tcx.for_each_relevant_impl(
+                            parent_def_id,
+                            parent_trait_ref.self_ty().skip_binder(),
+                            |impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) {
+                                Some(Node::Item(hir::Item {
+                                    kind: hir::ItemKind::Impl(hir::Impl { .. }),
+                                    ..
+                                })) => {
+                                    candidates.push(impl_def_id);
+                                }
+                                _ => {}
+                            },
+                        );
+                        if let [def_id] = &candidates[..] {
+                            match self.tcx.hir().get_if_local(*def_id) {
+                                Some(Node::Item(hir::Item {
+                                    kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                                    ..
+                                })) => {
+                                    if let Some(pred) = parent_p {
+                                        // Done to add the "doesn't satisfy" `span_label`.
+                                        let _ = format_pred(*pred);
+                                    }
+                                    skip_list.insert(p);
+                                    let mut spans = Vec::with_capacity(2);
+                                    if let Some(trait_ref) = of_trait {
+                                        spans.push(trait_ref.path.span);
+                                    }
+                                    spans.push(self_ty.span);
+                                    let entry = spanned_predicates.entry(spans.into());
+                                    entry
+                                        .or_insert_with(|| (path, tr_self_ty, Vec::new()))
+                                        .2
+                                        .push(p);
+                                }
+                                _ => {}
+                            }
+                        }
+                    }
+                    for (span, (path, self_ty, preds)) in spanned_predicates {
+                        err.span_note(
+                            span,
+                            &format!(
+                                "the following trait bounds were not satisfied because of the \
+                                 requirements of the implementation of `{}` for `{}`:\n{}",
+                                path,
+                                self_ty,
+                                preds
+                                    .into_iter()
+                                    // .map(|pred| format!("{:?}", pred))
+                                    .filter_map(|pred| format_pred(*pred))
+                                    .map(|(p, _)| format!("`{}`", p))
+                                    .collect::<Vec<_>>()
+                                    .join("\n"),
+                            ),
+                        );
+                    }
+
+                    // The requirements that didn't have an `impl` span to show.
                     let mut bound_list = unsatisfied_predicates
                         .iter()
-                        .filter_map(|(pred, parent_pred)| {
-                            format_pred(*pred).map(|(p, self_ty)| match parent_pred {
-                                None => format!("`{}`", &p),
-                                Some(parent_pred) => match format_pred(*parent_pred) {
+                        .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
+                        .filter_map(|(pred, parent_pred, _cause)| {
+                            format_pred(*pred).map(|(p, self_ty)| {
+                                collect_type_param_suggestions(self_ty, pred, &p);
+                                match parent_pred {
                                     None => format!("`{}`", &p),
-                                    Some((parent_p, _)) => {
-                                        collect_type_param_suggestions(self_ty, parent_pred, &p);
-                                        format!("`{}`\nwhich is required by `{}`", p, parent_p)
-                                    }
-                                },
+                                    Some(parent_pred) => match format_pred(*parent_pred) {
+                                        None => format!("`{}`", &p),
+                                        Some((parent_p, _)) => {
+                                            collect_type_param_suggestions(
+                                                self_ty,
+                                                parent_pred,
+                                                &p,
+                                            );
+                                            format!("`{}`\nwhich is required by `{}`", p, parent_p)
+                                        }
+                                    },
+                                }
                             })
                         })
                         .enumerate()
                         .collect::<Vec<(usize, String)>>();
+
                     for ((span, empty_where), obligations) in type_params.into_iter() {
                         restrict_type_params = true;
                         // #74886: Sort here so that the output is always the same.
@@ -836,7 +937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     for (span, msg) in bound_spans.into_iter() {
                         err.span_label(span, &msg);
                     }
-                    if !bound_list.is_empty() {
+                    if !bound_list.is_empty() || !skip_list.is_empty() {
                         let bound_list = bound_list
                             .into_iter()
                             .map(|(_, path)| path)
@@ -846,9 +947,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         err.set_primary_message(&format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
-                        err.note(&format!(
-                            "the following trait bounds were not satisfied:\n{bound_list}"
-                        ));
+                        if !bound_list.is_empty() {
+                            err.note(&format!(
+                                "the following trait bounds were not satisfied:\n{bound_list}"
+                            ));
+                        }
                         self.suggest_derive(&mut err, &unsatisfied_predicates);
 
                         unsatisfied_bounds = true;
@@ -1062,18 +1165,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.span_note(spans, &msg);
         }
 
-        let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect();
+        let preds: Vec<_> = errors
+            .iter()
+            .map(|e| (e.obligation.predicate, None, Some(e.obligation.cause.clone())))
+            .collect();
         self.suggest_derive(err, &preds);
     }
 
     fn suggest_derive(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+        unsatisfied_predicates: &Vec<(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )>,
     ) {
         let mut derives = Vec::<(String, Span, String)>::new();
         let mut traits = Vec::<Span>::new();
-        for (pred, _) in unsatisfied_predicates {
+        for (pred, _, _) in unsatisfied_predicates {
             let trait_pred = match pred.kind().skip_binder() {
                 ty::PredicateKind::Trait(trait_pred) => trait_pred,
                 _ => continue,
@@ -1264,7 +1374,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         item_name: Ident,
         source: SelfSource<'tcx>,
         valid_out_of_scope_traits: Vec<DefId>,
-        unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
+        unsatisfied_predicates: &[(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )],
         unsatisfied_bounds: bool,
     ) {
         let mut alt_rcvr_sugg = false;
@@ -1380,7 +1494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // this isn't perfect (that is, there are cases when
                 // implementing a trait would be legal but is rejected
                 // here).
-                unsatisfied_predicates.iter().all(|(p, _)| {
+                unsatisfied_predicates.iter().all(|(p, _, _)| {
                     match p.kind().skip_binder() {
                         // Hide traits if they are present in predicates as they can be fixed without
                         // having to implement them.
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 209690ec5fc..b9db8a6be59 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1990,16 +1990,12 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
         // prove that the trait applies to the types that were
         // used, and adding the predicate into this list ensures
         // that this is done.
-        let mut span = tcx.def_span(def_id);
-        if tcx.sess.source_map().is_local_span(span) {
-            // `guess_head_span` reads the actual source file from
-            // disk to try to determine the 'head' snippet of the span.
-            // Don't do this for a span that comes from a file outside
-            // of our crate, since this would make our query output
-            // (and overall crate metadata) dependent on the
-            // *current* state of an external file.
-            span = tcx.sess.source_map().guess_head_span(span);
-        }
+        //
+        // We use a DUMMY_SP here as a way to signal trait bounds that come
+        // from the trait itself that *shouldn't* be shown as the source of
+        // an obligation and instead be skipped. Otherwise we'd use
+        // `tcx.def_span(def_id);`
+        let span = rustc_span::DUMMY_SP;
         result.predicates =
             tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
                 ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx),
@@ -2865,14 +2861,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         } else if attr.has_name(sym::link_name) {
             codegen_fn_attrs.link_name = attr.value_str();
         } else if attr.has_name(sym::link_ordinal) {
-            if link_ordinal_span.is_some() {
-                tcx.sess
-                    .struct_span_err(
-                        attr.span,
-                        "multiple `link_ordinal` attributes on a single definition",
-                    )
-                    .emit();
-            }
             link_ordinal_span = Some(attr.span);
             if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
                 codegen_fn_attrs.link_ordinal = ordinal;