diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 9444fffc331c7..7cbfe143b4d83 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -1,8 +1,8 @@
 use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
-use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
+use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
 use rustc_hir as hir;
 use rustc_session::parse::feature_err;
-use rustc_span::{sym, DesugaringKind};
+use rustc_span::sym;
 
 use smallvec::SmallVec;
 
@@ -36,21 +36,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             match s.kind {
                 StmtKind::Local(ref local) => {
                     let hir_id = self.lower_node_id(s.id);
-                    match &local.kind {
-                        LocalKind::InitElse(init, els) => {
-                            let e = self.lower_let_else(hir_id, local, init, els, tail);
-                            expr = Some(e);
-                            // remaining statements are in let-else expression
-                            break;
-                        }
-                        _ => {
-                            let local = self.lower_local(local);
-                            self.alias_attrs(hir_id, local.hir_id);
-                            let kind = hir::StmtKind::Local(local);
-                            let span = self.lower_span(s.span);
-                            stmts.push(hir::Stmt { hir_id, kind, span });
-                        }
-                    }
+                    let local = self.lower_local(local);
+                    self.alias_attrs(hir_id, local.hir_id);
+                    let kind = hir::StmtKind::Local(local);
+                    let span = self.lower_span(s.span);
+                    stmts.push(hir::Stmt { hir_id, kind, span });
                 }
                 StmtKind::Item(ref it) => {
                     stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
@@ -101,10 +91,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let init = l.kind.init().map(|init| self.lower_expr(init));
         let hir_id = self.lower_node_id(l.id);
         let pat = self.lower_pat(&l.pat);
+        let els = if let LocalKind::InitElse(_, els) = &l.kind {
+            if !self.tcx.features().let_else {
+                feature_err(
+                    &self.tcx.sess.parse_sess,
+                    sym::let_else,
+                    l.span,
+                    "`let...else` statements are unstable",
+                )
+                .emit();
+            }
+            Some(self.lower_block(els, false))
+        } else {
+            None
+        };
         let span = self.lower_span(l.span);
         let source = hir::LocalSource::Normal;
         self.lower_attrs(hir_id, &l.attrs);
-        self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source })
+        self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source })
     }
 
     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
@@ -115,59 +119,4 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
     }
-
-    fn lower_let_else(
-        &mut self,
-        stmt_hir_id: hir::HirId,
-        local: &Local,
-        init: &Expr,
-        els: &Block,
-        tail: &[Stmt],
-    ) -> &'hir hir::Expr<'hir> {
-        let ty = local
-            .ty
-            .as_ref()
-            .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
-        let span = self.lower_span(local.span);
-        let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
-        let init = self.lower_expr(init);
-        let local_hir_id = self.lower_node_id(local.id);
-        self.lower_attrs(local_hir_id, &local.attrs);
-        let let_expr = {
-            let lex = self.arena.alloc(hir::Let {
-                hir_id: local_hir_id,
-                pat: self.lower_pat(&local.pat),
-                ty,
-                init,
-                span,
-            });
-            self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new()))
-        };
-        let then_expr = {
-            let (stmts, expr) = self.lower_stmts(tail);
-            let block = self.block_all(span, stmts, expr);
-            self.arena.alloc(self.expr_block(block, AttrVec::new()))
-        };
-        let else_expr = {
-            let block = self.lower_block(els, false);
-            self.arena.alloc(self.expr_block(block, AttrVec::new()))
-        };
-        self.alias_attrs(let_expr.hir_id, local_hir_id);
-        self.alias_attrs(else_expr.hir_id, local_hir_id);
-        let if_expr = self.arena.alloc(hir::Expr {
-            hir_id: stmt_hir_id,
-            span,
-            kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
-        });
-        if !self.tcx.features().let_else {
-            feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::let_else,
-                local.span,
-                "`let...else` statements are unstable",
-            )
-            .emit();
-        }
-        if_expr
-    }
 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index fdf60e60914a4..4da3096f7c3aa 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2146,7 +2146,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             debug_assert!(!a.is_empty());
             self.attrs.insert(hir_id.local_id, a);
         }
-        let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
+        let local = hir::Local {
+            hir_id,
+            init,
+            pat,
+            els: None,
+            source,
+            span: self.lower_span(span),
+            ty: None,
+        };
         self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
     }
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index ce7c0eb72cd24..6673d75d99df0 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -856,7 +856,6 @@ pub enum ReprAttr {
     ReprSimd,
     ReprTransparent,
     ReprAlign(u32),
-    ReprNoNiche,
 }
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
@@ -904,7 +903,6 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     sym::packed => Some(ReprPacked(1)),
                     sym::simd => Some(ReprSimd),
                     sym::transparent => Some(ReprTransparent),
-                    sym::no_niche => Some(ReprNoNiche),
                     sym::align => {
                         let mut err = struct_span_err!(
                             diagnostic,
@@ -943,7 +941,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         Ok(literal) => acc.push(ReprPacked(literal)),
                         Err(message) => literal_error = Some(message),
                     };
-                } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
+                } else if matches!(name, sym::C | sym::simd | sym::transparent)
                     || int_type_of_word(name).is_some()
                 {
                     recognised = true;
@@ -1001,7 +999,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     } else {
                         if matches!(
                             meta_item.name_or_empty(),
-                            sym::C | sym::simd | sym::transparent | sym::no_niche
+                            sym::C | sym::simd | sym::transparent
                         ) || int_type_of_word(meta_item.name_or_empty()).is_some()
                         {
                             recognised = true;
@@ -1039,7 +1037,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         .emit();
                     } else if matches!(
                         meta_item.name_or_empty(),
-                        sym::C | sym::simd | sym::transparent | sym::no_niche
+                        sym::C | sym::simd | sym::transparent
                     ) || int_type_of_word(meta_item.name_or_empty()).is_some()
                     {
                         recognised = true;
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 9dfdafcb38e0b..7616e7a63d107 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         }
 
         if let Some(def) = mplace.layout.ty.ty_adt_def() {
-            if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() {
+            if def.is_unsafe_cell() {
                 // We are crossing over an `UnsafeCell`, we can mutate again. This means that
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 5114ce5d452b3..53bc2cc8a6980 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -821,7 +821,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         // Special check preventing `UnsafeCell` in the inner part of constants
         if let Some(def) = op.layout.ty.ty_adt_def() {
             if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
-                && Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type()
+                && def.is_unsafe_cell()
             {
                 throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
             }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 0aa7b117b89ba..a6f21ccef6d20 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -96,13 +96,13 @@ impl Qualif for HasMutInterior {
     }
 
     fn in_adt_inherently<'tcx>(
-        cx: &ConstCx<'_, 'tcx>,
+        _cx: &ConstCx<'_, 'tcx>,
         adt: AdtDef<'tcx>,
         _: SubstsRef<'tcx>,
     ) -> bool {
         // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
         // It arises structurally for all other types.
-        Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type()
+        adt.is_unsafe_cell()
     }
 }
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index b54f0ef361a8d..117bdad971a20 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -156,9 +156,6 @@ declare_features! (
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
-    /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`,
-    /// it is not on path for eventual stabilization).
-    (active, no_niche, "1.42.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
     /// Allows using `#[prelude_import]` on glob `use` items.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 04f585df34cc2..ed874ae829b46 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1316,6 +1316,8 @@ pub struct Local<'hir> {
     pub ty: Option<&'hir Ty<'hir>>,
     /// Initializer expression to set the value, if any.
     pub init: Option<&'hir Expr<'hir>>,
+    /// Else block for a `let...else` binding.
+    pub els: Option<&'hir Block<'hir>>,
     pub hir_id: HirId,
     pub span: Span,
     /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 531d9f1404021..b5d9769c578a5 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -472,6 +472,9 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
     walk_list!(visitor, visit_expr, &local.init);
     visitor.visit_id(local.hir_id);
     visitor.visit_pat(&local.pat);
+    if let Some(els) = local.els {
+        visitor.visit_block(els);
+    }
     walk_list!(visitor, visit_ty, &local.ty);
 }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 50acb0270b0be..e3c97ec357e87 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -883,7 +883,12 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
     }
 
-    pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) {
+    pub fn print_local(
+        &mut self,
+        init: Option<&hir::Expr<'_>>,
+        els: Option<&hir::Block<'_>>,
+        decl: impl Fn(&mut Self),
+    ) {
         self.space_if_not_bol();
         self.ibox(INDENT_UNIT);
         self.word_nbsp("let");
@@ -897,6 +902,13 @@ impl<'a> State<'a> {
             self.word_space("=");
             self.print_expr(init);
         }
+
+        if let Some(els) = els {
+            self.nbsp();
+            self.word_space("else");
+            self.print_block(els);
+        }
+
         self.end()
     }
 
@@ -904,7 +916,7 @@ impl<'a> State<'a> {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
             hir::StmtKind::Local(loc) => {
-                self.print_local(loc.init, |this| this.print_local_decl(loc));
+                self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc));
             }
             hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
             hir::StmtKind::Expr(expr) => {
@@ -1404,7 +1416,7 @@ impl<'a> State<'a> {
 
                 // Print `let _t = $init;`:
                 let temp = Ident::from_str("_t");
-                self.print_local(Some(init), |this| this.print_ident(temp));
+                self.print_local(Some(init), None, |this| this.print_ident(temp));
                 self.word(";");
 
                 // Print `_t`:
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index be4843c7ff153..aca481df2e113 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -703,9 +703,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
                 return true;
             }
 
-            // Types with a `#[repr(no_niche)]` attribute have their niche hidden.
-            // The attribute is used by the UnsafeCell for example (the only use so far).
-            if def.repr().hide_niche() {
+            // `UnsafeCell` has its niche hidden.
+            if def.is_unsafe_cell() {
                 return false;
             }
 
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 3fe6394ad7e9c..3e5f6bb8f0bcf 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -182,6 +182,9 @@ pub enum StmtKind<'tcx> {
         /// `let pat: ty = <INIT>`
         initializer: Option<ExprId>,
 
+        /// `let pat: ty = <INIT> else { <ELSE> }
+        else_block: Option<Block>,
+
         /// The lint level for this `let` statement.
         lint_level: LintLevel,
     },
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index c8d09875c2896..97249fdd17563 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -167,11 +167,15 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm
             init_scope: _,
             ref pattern,
             lint_level: _,
+            else_block,
         } => {
             if let Some(init) = initializer {
                 visitor.visit_expr(&visitor.thir()[*init]);
             }
             visitor.visit_pat(pattern);
+            if let Some(block) = else_block {
+                visitor.visit_block(block)
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 4cac767073577..809406aff1878 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -52,6 +52,8 @@ bitflags! {
         /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
         /// (i.e., this flag is never set unless this ADT is an enum).
         const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
+        /// Indicates whether the type is `UnsafeCell`.
+        const IS_UNSAFE_CELL              = 1 << 9;
     }
 }
 
@@ -247,6 +249,9 @@ impl AdtDefData {
         if Some(did) == tcx.lang_items().manually_drop() {
             flags |= AdtFlags::IS_MANUALLY_DROP;
         }
+        if Some(did) == tcx.lang_items().unsafe_cell_type() {
+            flags |= AdtFlags::IS_UNSAFE_CELL;
+        }
 
         AdtDefData { did, variants, flags, repr }
     }
@@ -333,6 +338,12 @@ impl<'tcx> AdtDef<'tcx> {
         self.flags().contains(AdtFlags::IS_BOX)
     }
 
+    /// Returns `true` if this is UnsafeCell<T>.
+    #[inline]
+    pub fn is_unsafe_cell(self) -> bool {
+        self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
+    }
+
     /// Returns `true` if this is `ManuallyDrop<T>`.
     #[inline]
     pub fn is_manually_drop(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f87b6e4212d29..1ed41db099ca0 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -542,14 +542,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             debug!("univariant offset: {:?} field: {:#?}", offset, field);
             offsets[i as usize] = offset;
 
-            if !repr.hide_niche() {
-                if let Some(mut niche) = field.largest_niche {
-                    let available = niche.available(dl);
-                    if available > largest_niche_available {
-                        largest_niche_available = available;
-                        niche.offset += offset;
-                        largest_niche = Some(niche);
-                    }
+            if let Some(mut niche) = field.largest_niche {
+                let available = niche.available(dl);
+                if available > largest_niche_available {
+                    largest_niche_available = available;
+                    niche.offset += offset;
+                    largest_niche = Some(niche);
                 }
             }
 
@@ -1078,6 +1076,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                     let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?;
                     st.variants = Variants::Single { index: v };
+
+                    if def.is_unsafe_cell() {
+                        let hide_niches = |scalar: &mut _| match scalar {
+                            Scalar::Initialized { value, valid_range } => {
+                                *valid_range = WrappingRange::full(value.size(dl))
+                            }
+                            // Already doesn't have any niches
+                            Scalar::Union { .. } => {}
+                        };
+                        match &mut st.abi {
+                            Abi::Uninhabited => {}
+                            Abi::Scalar(scalar) => hide_niches(scalar),
+                            Abi::ScalarPair(a, b) => {
+                                hide_niches(a);
+                                hide_niches(b);
+                            }
+                            Abi::Vector { element, count: _ } => hide_niches(element),
+                            Abi::Aggregate { sized: _ } => {}
+                        }
+                        st.largest_niche = None;
+                        return Ok(tcx.intern_layout(st));
+                    }
+
                     let (start, end) = self.tcx.layout_scalar_valid_range(def.did());
                     match st.abi {
                         Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
@@ -1106,11 +1127,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                             }
 
                             // Update `largest_niche` if we have introduced a larger niche.
-                            let niche = if def.repr().hide_niche() {
-                                None
-                            } else {
-                                Niche::from_scalar(dl, Size::ZERO, *scalar)
-                            };
+                            let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
                             if let Some(niche) = niche {
                                 match st.largest_niche {
                                     Some(largest_niche) => {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f15108fb7501a..c2c7b3df844ad 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1720,11 +1720,9 @@ bitflags! {
         const IS_TRANSPARENT     = 1 << 2;
         // Internal only for now. If true, don't reorder fields.
         const IS_LINEAR          = 1 << 3;
-        // If true, don't expose any niche to type's context.
-        const HIDE_NICHE         = 1 << 4;
         // If true, the type's layout can be randomized using
         // the seed stored in `ReprOptions.layout_seed`
-        const RANDOMIZE_LAYOUT   = 1 << 5;
+        const RANDOMIZE_LAYOUT   = 1 << 4;
         // Any of these flags being set prevent field reordering optimisation.
         const IS_UNOPTIMISABLE   = ReprFlags::IS_C.bits
                                  | ReprFlags::IS_SIMD.bits
@@ -1781,7 +1779,6 @@ impl ReprOptions {
                         ReprFlags::empty()
                     }
                     attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
-                    attr::ReprNoNiche => ReprFlags::HIDE_NICHE,
                     attr::ReprSimd => ReprFlags::IS_SIMD,
                     attr::ReprInt(i) => {
                         size = Some(i);
@@ -1834,11 +1831,6 @@ impl ReprOptions {
         self.flags.contains(ReprFlags::IS_LINEAR)
     }
 
-    #[inline]
-    pub fn hide_niche(&self) -> bool {
-        self.flags.contains(ReprFlags::HIDE_NICHE)
-    }
-
     /// Returns the discriminant type, given these `repr` options.
     /// This must only be called on enums!
     pub fn discr_type(&self) -> attr::IntType {
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index a83328c0cabc6..cb8be51a08562 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     ref pattern,
                     initializer,
                     lint_level,
+                    else_block,
                 } => {
                     let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result });
@@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 |this| {
                                     let scope = (*init_scope, source_info);
                                     this.in_scope(scope, *lint_level, |this| {
-                                        this.declare_bindings(
-                                            visibility_scope,
-                                            remainder_span,
-                                            pattern,
-                                            ArmHasGuard(false),
-                                            Some((None, initializer_span)),
-                                        );
-                                        this.expr_into_pattern(block, pattern.clone(), init)
+                                        if let Some(else_block) = else_block {
+                                            this.ast_let_else(
+                                                block,
+                                                init,
+                                                initializer_span,
+                                                else_block,
+                                                visibility_scope,
+                                                remainder_span,
+                                                pattern,
+                                            )
+                                        } else {
+                                            this.declare_bindings(
+                                                visibility_scope,
+                                                remainder_span,
+                                                pattern,
+                                                ArmHasGuard(false),
+                                                Some((None, initializer_span)),
+                                            );
+                                            this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
+                                        }
                                     })
-                                }
+                                },
                             )
-                        );
+                        )
                     } else {
                         let scope = (*init_scope, source_info);
                         unpack!(this.in_scope(scope, *lint_level, |this| {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 1628f1a4b850b..7067a48b783ec 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1615,7 +1615,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // those N possible outcomes, create a (initially empty)
         // vector of candidates. Those are the candidates that still
         // apply if the test has that particular outcome.
-        debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
+        debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair);
         let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
         target_candidates.resize_with(test.targets(), Default::default);
 
@@ -1635,8 +1635,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
         // at least the first candidate ought to be tested
         assert!(total_candidate_count > candidates.len());
-        debug!("tested_candidates: {}", total_candidate_count - candidates.len());
-        debug!("untested_candidates: {}", candidates.len());
+        debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
+        debug!("test_candidates: untested_candidates: {}", candidates.len());
 
         // HACK(matthewjasper) This is a closure so that we can let the test
         // create its blocks before the rest of the match. This currently
@@ -2274,4 +2274,75 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!("declare_binding: vars={:?}", locals);
         self.var_indices.insert(var_id, locals);
     }
+
+    pub(crate) fn ast_let_else(
+        &mut self,
+        mut block: BasicBlock,
+        init: &Expr<'tcx>,
+        initializer_span: Span,
+        else_block: &Block,
+        visibility_scope: Option<SourceScope>,
+        remainder_span: Span,
+        pattern: &Pat<'tcx>,
+    ) -> BlockAnd<()> {
+        let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span));
+        let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) };
+        let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
+        self.declare_bindings(
+            visibility_scope,
+            remainder_span,
+            pattern,
+            ArmHasGuard(false),
+            Some((None, initializer_span)),
+        );
+        let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
+        let fake_borrow_temps = self.lower_match_tree(
+            block,
+            initializer_span,
+            pattern.span,
+            false,
+            &mut [&mut candidate, &mut wildcard],
+        );
+        // This block is for the matching case
+        let matching = self.bind_pattern(
+            self.source_info(pattern.span),
+            candidate,
+            None,
+            &fake_borrow_temps,
+            initializer_span,
+            None,
+            None,
+            None,
+        );
+        // This block is for the failure case
+        let failure = self.bind_pattern(
+            self.source_info(else_block.span),
+            wildcard,
+            None,
+            &fake_borrow_temps,
+            initializer_span,
+            None,
+            None,
+            None,
+        );
+        // This place is not really used because this destination place
+        // should never be used to take values at the end of the failure
+        // block.
+        let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
+        let failure_block;
+        unpack!(
+            failure_block = self.ast_block(
+                dummy_place,
+                failure,
+                else_block,
+                self.source_info(else_block.span),
+            )
+        );
+        self.cfg.terminate(
+            failure_block,
+            self.source_info(else_block.span),
+            TerminatorKind::Unreachable,
+        );
+        matching.unit()
+    }
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 59750d5d0b88e..dccaa61ed89d4 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -74,6 +74,8 @@ impl<'tcx> Cx<'tcx> {
                             )),
                         };
 
+                        let else_block = local.els.map(|els| self.mirror_block(els));
+
                         let mut pattern = self.pattern_from_hir(local.pat);
                         debug!(?pattern);
 
@@ -110,6 +112,7 @@ impl<'tcx> Cx<'tcx> {
                                 },
                                 pattern,
                                 initializer: local.init.map(|init| self.mirror_expr(init)),
+                                else_block,
                                 lint_level: LintLevel::Explicit(local.hir_id),
                             },
                             opt_destruction_scope: opt_dxn_ext,
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 75fd156ebfdf3..5bd1fad0bcb9f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{
 };
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
-use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span};
+use rustc_span::{BytePos, Span};
 
 pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match def_id.as_local() {
@@ -77,6 +77,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
 
     fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) {
         intravisit::walk_local(self, loc);
+        let els = loc.els;
+        if let Some(init) = loc.init && els.is_some() {
+            self.check_let(&loc.pat, init, loc.span);
+        }
 
         let (msg, sp) = match loc.source {
             hir::LocalSource::Normal => ("local binding", Some(loc.span)),
@@ -84,7 +88,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
             hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
         };
-        self.check_irrefutable(&loc.pat, msg, sp);
+        if els.is_none() {
+            self.check_irrefutable(&loc.pat, msg, sp);
+        }
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
@@ -1125,17 +1131,16 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
         }) if Some(*hir_id) == pat_id => {
             return LetSource::IfLetGuard;
         }
-        hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
-            let expn_data = span.ctxt().outer_expn_data();
-            if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind {
-                return LetSource::LetElse(expn_data.call_site);
-            }
-        }
         _ => {}
     }
 
     let parent_parent = hir.get_parent_node(parent);
     let parent_parent_node = hir.get(parent_parent);
+    if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
+        parent_parent_node
+    {
+        return LetSource::LetElse(*span);
+    }
 
     let parent_parent_parent = hir.get_parent_node(parent_parent);
     let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index efa45883eab4b..c48aa9a90efbe 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -102,7 +102,7 @@ fn is_needs_drop_and_init<'tcx>(
     let field_needs_drop_and_init = |(f, f_ty, mpi)| {
         let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f));
         let Some(mpi) = child else {
-            return f_ty.needs_drop(tcx, param_env);
+            return Ty::needs_drop(f_ty, tcx, param_env);
         };
 
         is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi)
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d0723c68a77e8..20d03d797fed1 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1808,21 +1808,6 @@ impl CheckAttrVisitor<'_> {
                         _ => ("a", "struct, enum, or union"),
                     }
                 }
-                sym::no_niche => {
-                    if !self.tcx.features().enabled(sym::no_niche) {
-                        feature_err(
-                            &self.tcx.sess.parse_sess,
-                            sym::no_niche,
-                            hint.span(),
-                            "the attribute `repr(no_niche)` is currently unstable",
-                        )
-                        .emit();
-                    }
-                    match target {
-                        Target::Struct | Target::Enum => continue,
-                        _ => ("a", "struct or enum"),
-                    }
-                }
                 sym::i8
                 | sym::u8
                 | sym::i16
@@ -1870,10 +1855,8 @@ impl CheckAttrVisitor<'_> {
         // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
         let hint_spans = hints.iter().map(|hint| hint.span());
 
-        // Error on repr(transparent, <anything else apart from no_niche>).
-        let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche;
-        let non_no_niche_count = hints.iter().filter(non_no_niche).count();
-        if is_transparent && non_no_niche_count > 1 {
+        // Error on repr(transparent, <anything else>).
+        if is_transparent && hints.len() > 1 {
             let hint_spans: Vec<_> = hint_spans.clone().collect();
             struct_span_err!(
                 self.tcx.sess,
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 0070c0699a4aa..eed3e1579a231 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -278,7 +278,7 @@ impl<'tcx> IrMaps<'tcx> {
                     pats.extend(inner_pat.iter());
                 }
                 Struct(_, fields, _) => {
-                    let (short, not_short): (Vec<&_>, Vec<&_>) =
+                    let (short, not_short): (Vec<_>, _) =
                         fields.iter().partition(|f| f.is_shorthand);
                     shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id));
                     pats.extend(not_short.iter().map(|f| f.pat));
@@ -298,7 +298,7 @@ impl<'tcx> IrMaps<'tcx> {
             }
         }
 
-        return shorthand_field_ids;
+        shorthand_field_ids
     }
 
     fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
@@ -368,6 +368,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
 
     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
         self.add_from_pat(&local.pat);
+        if local.els.is_some() {
+            self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id));
+        }
         intravisit::walk_local(self, local);
     }
 
@@ -800,8 +803,40 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 // initialization, which is mildly more complex than checking
                 // once at the func header but otherwise equivalent.
 
-                let succ = self.propagate_through_opt_expr(local.init, succ);
-                self.define_bindings_in_pat(&local.pat, succ)
+                if let Some(els) = local.els {
+                    // Eventually, `let pat: ty = init else { els };` is mostly equivalent to
+                    // `let (bindings, ...) = match init { pat => (bindings, ...), _ => els };`
+                    // except that extended lifetime applies at the `init` location.
+                    //
+                    //       (e)
+                    //        |
+                    //        v
+                    //      (expr)
+                    //      /   \
+                    //     |     |
+                    //     v     v
+                    // bindings  els
+                    //     |
+                    //     v
+                    // ( succ )
+                    //
+                    if let Some(init) = local.init {
+                        let else_ln = self.propagate_through_block(els, succ);
+                        let ln = self.live_node(local.hir_id, local.span);
+                        self.init_from_succ(ln, succ);
+                        self.merge_from_succ(ln, else_ln);
+                        let succ = self.propagate_through_expr(init, ln);
+                        self.define_bindings_in_pat(&local.pat, succ)
+                    } else {
+                        span_bug!(
+                            stmt.span,
+                            "variable is uninitialized but an unexpected else branch is found"
+                        )
+                    }
+                } else {
+                    let succ = self.propagate_through_opt_expr(local.init, succ);
+                    self.define_bindings_in_pat(&local.pat, succ)
+                }
             }
             hir::StmtKind::Item(..) => succ,
             hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
@@ -1121,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         //     (rvalue)          ||       (rvalue)
         //         |             ||           |
         //         v             ||           v
-        // (write of place)     ||   (place components)
+        // (write of place)      ||   (place components)
         //         |             ||           |
         //         v             ||           v
         //      (succ)           ||        (succ)
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 6eb2f2d929d57..a4175f4c5f377 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -82,14 +82,7 @@ impl<'tcx> DumpVisitor<'tcx> {
     pub fn new(save_ctxt: SaveContext<'tcx>) -> DumpVisitor<'tcx> {
         let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
         let dumper = Dumper::new(save_ctxt.config.clone());
-        DumpVisitor {
-            tcx: save_ctxt.tcx,
-            save_ctxt,
-            dumper,
-            span: span_utils,
-            // mac_defs: FxHashSet::default(),
-            // macro_calls: FxHashSet::default(),
-        }
+        DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils }
     }
 
     pub fn analysis(&self) -> &rls_data::Analysis {
@@ -1425,9 +1418,10 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
         self.process_macro_use(l.span);
         self.process_var_decl(&l.pat);
 
-        // Just walk the initializer and type (don't want to walk the pattern again).
+        // Just walk the initializer, the else branch and type (don't want to walk the pattern again).
         walk_list!(self, visit_ty, &l.ty);
         walk_list!(self, visit_expr, &l.init);
+        walk_list!(self, visit_block, l.els);
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 3df4dfb74b319..29879c48b04ae 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1141,7 +1141,6 @@ pub enum DesugaringKind {
     Async,
     Await,
     ForLoop,
-    LetElse,
     WhileLoop,
 }
 
@@ -1157,7 +1156,6 @@ impl DesugaringKind {
             DesugaringKind::YeetExpr => "`do yeet` expression",
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop => "`for` loop",
-            DesugaringKind::LetElse => "`let...else`",
             DesugaringKind::WhileLoop => "`while` loop",
         }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9b6967621f1dc..99912b491cb7d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -980,7 +980,6 @@ symbols! {
         no_link,
         no_main,
         no_mangle,
-        no_niche,
         no_sanitize,
         no_stack_check,
         no_start,
@@ -1153,7 +1152,6 @@ symbols! {
         repr128,
         repr_align,
         repr_align_enum,
-        repr_no_niche,
         repr_packed,
         repr_simd,
         repr_transparent,
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 33585de600130..b08fc48218602 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1311,7 +1311,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         visitor.visit_body(&body);
 
         let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
-        let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id) else { return false; };
+        let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
 
         let ret_types = visitor
             .returns
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 1d3608048f284..30b76b922c77a 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -997,26 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
 
         if let Some(else_expr) = opt_else_expr {
-            let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) {
-                // todo introduce `check_expr_with_expectation(.., Expectation::LetElse)`
-                //   for errors that point to the offending expression rather than the entire block.
-                //   We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no
-                //   way to detect that the expected type originated from let-else and provide
-                //   a customized error.
-                let else_ty = self.check_expr(else_expr);
-                let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse);
-
-                if let Some(mut err) =
-                    self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
-                {
-                    err.emit();
-                    self.tcx.ty_error()
-                } else {
-                    else_ty
-                }
-            } else {
-                self.check_expr_with_expectation(else_expr, expected)
-            };
+            let else_ty = self.check_expr_with_expectation(else_expr, expected);
             let else_diverges = self.diverges.get();
 
             let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index a7c7089234aa9..60ee2233ed9c0 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1215,6 +1215,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
         let pat_ty = self.node_ty(decl.pat.hir_id);
         self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
+
+        if let Some(blk) = decl.els {
+            let previous_diverges = self.diverges.get();
+            let else_ty = self.check_block_with_expected(blk, NoExpectation);
+            let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
+            if let Some(mut err) =
+                self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
+            {
+                err.emit();
+            }
+            self.diverges.set(previous_diverges);
+        }
     }
 
     /// Type check a `let` statement.
@@ -1236,8 +1248,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let old_has_errors = self.has_errors.replace(false);
 
         match stmt.kind {
-            hir::StmtKind::Local(ref l) => {
-                self.check_decl_local(&l);
+            hir::StmtKind::Local(l) => {
+                self.check_decl_local(l);
             }
             // Ignore for now.
             hir::StmtKind::Item(_) => {}
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs
index 576dc6f127cbd..8f34a970f6ff7 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_typeck/src/check/gather_locals.rs
@@ -16,19 +16,20 @@ pub(super) struct Declaration<'a> {
     pub ty: Option<&'a hir::Ty<'a>>,
     pub span: Span,
     pub init: Option<&'a hir::Expr<'a>>,
+    pub els: Option<&'a hir::Block<'a>>,
 }
 
 impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
     fn from(local: &'a hir::Local<'a>) -> Self {
-        let hir::Local { hir_id, pat, ty, span, init, .. } = *local;
-        Declaration { hir_id, pat, ty, span, init }
+        let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
+        Declaration { hir_id, pat, ty, span, init, els }
     }
 }
 
 impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
     fn from(let_expr: &'a hir::Let<'a>) -> Self {
         let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
-        Declaration { hir_id, pat, ty, span, init: Some(init) }
+        Declaration { hir_id, pat, ty, span, init: Some(init), els: None }
     }
 }
 
@@ -101,7 +102,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
     // Add explicitly-declared locals.
     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
         self.declare(local.into());
-        intravisit::walk_local(self, local);
+        intravisit::walk_local(self, local)
     }
 
     fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs
index 9f1368a3e0777..a1a92c62ad22f 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_typeck/src/check/region.rs
@@ -460,6 +460,7 @@ fn resolve_local<'tcx>(
     visitor: &mut RegionResolutionVisitor<'tcx>,
     pat: Option<&'tcx hir::Pat<'tcx>>,
     init: Option<&'tcx hir::Expr<'tcx>>,
+    els: Option<&'tcx hir::Block<'tcx>>,
 ) {
     debug!("resolve_local(pat={:?}, init={:?})", pat, init);
 
@@ -537,13 +538,18 @@ fn resolve_local<'tcx>(
         }
     }
 
-    // Make sure we visit the initializer first, so expr_and_pat_count remains correct
+    // Make sure we visit the initializer first, so expr_and_pat_count remains correct.
+    // The correct order, as shared between generator_interior, drop_ranges and intravisitor,
+    // is to walk initializer, followed by pattern bindings, finally followed by the `else` block.
     if let Some(expr) = init {
         visitor.visit_expr(expr);
     }
     if let Some(pat) = pat {
         visitor.visit_pat(pat);
     }
+    if let Some(els) = els {
+        visitor.visit_block(els);
+    }
 
     /// Returns `true` if `pat` match the `P&` non-terminal.
     ///
@@ -764,7 +770,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
             // (i.e., `'static`), which means that after `g` returns, it drops,
             // and all the associated destruction scope rules apply.
             self.cx.var_parent = None;
-            resolve_local(self, None, Some(&body.value));
+            resolve_local(self, None, Some(&body.value), None);
         }
 
         if body.generator_kind.is_some() {
@@ -791,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
         resolve_expr(self, ex);
     }
     fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
-        resolve_local(self, Some(&l.pat), l.init);
+        resolve_local(self, Some(&l.pat), l.init, l.els)
     }
 }
 
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 920e3d578c812..9d7420acd2662 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -2,7 +2,10 @@
 //! normal visitor, which just walks the entire body in one shot, the
 //! `ExprUseVisitor` determines how expressions are being used.
 
+use std::slice::from_ref;
+
 use hir::def::DefKind;
+use hir::Expr;
 // Export these here so that Clippy can use them.
 pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
 
@@ -252,96 +255,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             }
 
             hir::ExprKind::Let(hir::Let { pat, init, .. }) => {
-                self.walk_local(init, pat, |t| t.borrow_expr(init, ty::ImmBorrow));
+                self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow))
             }
 
             hir::ExprKind::Match(ref discr, arms, _) => {
                 let discr_place = return_if_err!(self.mc.cat_expr(discr));
-
-                // Matching should not always be considered a use of the place, hence
-                // discr does not necessarily need to be borrowed.
-                // We only want to borrow discr if the pattern contain something other
-                // than wildcards.
-                let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
-                let mut needs_to_be_read = false;
-                for arm in arms.iter() {
-                    return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| {
-                        match &pat.kind {
-                            PatKind::Binding(.., opt_sub_pat) => {
-                                // If the opt_sub_pat is None, than the binding does not count as
-                                // a wildcard for the purpose of borrowing discr.
-                                if opt_sub_pat.is_none() {
-                                    needs_to_be_read = true;
-                                }
-                            }
-                            PatKind::Path(qpath) => {
-                                // A `Path` pattern is just a name like `Foo`. This is either a
-                                // named constant or else it refers to an ADT variant
-
-                                let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
-                                match res {
-                                    Res::Def(DefKind::Const, _)
-                                    | Res::Def(DefKind::AssocConst, _) => {
-                                        // Named constants have to be equated with the value
-                                        // being matched, so that's a read of the value being matched.
-                                        //
-                                        // FIXME: We don't actually  reads for ZSTs.
-                                        needs_to_be_read = true;
-                                    }
-                                    _ => {
-                                        // Otherwise, this is a struct/enum variant, and so it's
-                                        // only a read if we need to read the discriminant.
-                                        needs_to_be_read |= is_multivariant_adt(place.place.ty());
-                                    }
-                                }
-                            }
-                            PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
-                                // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
-                                // against a multivariant enum or struct. In that case, we have to read
-                                // the discriminant. Otherwise this kind of pattern doesn't actually
-                                // read anything (we'll get invoked for the `...`, which may indeed
-                                // perform some reads).
-
-                                let place_ty = place.place.ty();
-                                needs_to_be_read |= is_multivariant_adt(place_ty);
-                            }
-                            PatKind::Lit(_) | PatKind::Range(..) => {
-                                // If the PatKind is a Lit or a Range then we want
-                                // to borrow discr.
-                                needs_to_be_read = true;
-                            }
-                            PatKind::Or(_)
-                            | PatKind::Box(_)
-                            | PatKind::Slice(..)
-                            | PatKind::Ref(..)
-                            | PatKind::Wild => {
-                                // If the PatKind is Or, Box, Slice or Ref, the decision is made later
-                                // as these patterns contains subpatterns
-                                // If the PatKind is Wild, the decision is made based on the other patterns being
-                                // examined
-                            }
-                        }
-                    }));
-                }
-
-                if needs_to_be_read {
-                    self.borrow_expr(discr, ty::ImmBorrow);
-                } else {
-                    let closure_def_id = match discr_place.place.base {
-                        PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
-                        _ => None,
-                    };
-
-                    self.delegate.fake_read(
-                        &discr_place,
-                        FakeReadCause::ForMatchedPlace(closure_def_id),
-                        discr_place.hir_id,
-                    );
-
-                    // We always want to walk the discriminant. We want to make sure, for instance,
-                    // that the discriminant has been initialized.
-                    self.walk_expr(discr);
-                }
+                self.maybe_read_scrutinee(
+                    discr,
+                    discr_place.clone(),
+                    arms.iter().map(|arm| arm.pat),
+                );
 
                 // treatment of the discriminant is handled while walking the arms.
                 for arm in arms {
@@ -453,8 +376,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
     fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
         match stmt.kind {
-            hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => {
-                self.walk_local(expr, pat, |_| {});
+            hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => {
+                self.walk_local(expr, pat, *els, |_| {})
             }
 
             hir::StmtKind::Local(_) => {}
@@ -470,13 +393,114 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         }
     }
 
-    fn walk_local<F>(&mut self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, mut f: F)
-    where
+    fn maybe_read_scrutinee<'t>(
+        &mut self,
+        discr: &Expr<'_>,
+        discr_place: PlaceWithHirId<'tcx>,
+        pats: impl Iterator<Item = &'t hir::Pat<'t>>,
+    ) {
+        // Matching should not always be considered a use of the place, hence
+        // discr does not necessarily need to be borrowed.
+        // We only want to borrow discr if the pattern contain something other
+        // than wildcards.
+        let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
+        let mut needs_to_be_read = false;
+        for pat in pats {
+            return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
+                match &pat.kind {
+                    PatKind::Binding(.., opt_sub_pat) => {
+                        // If the opt_sub_pat is None, than the binding does not count as
+                        // a wildcard for the purpose of borrowing discr.
+                        if opt_sub_pat.is_none() {
+                            needs_to_be_read = true;
+                        }
+                    }
+                    PatKind::Path(qpath) => {
+                        // A `Path` pattern is just a name like `Foo`. This is either a
+                        // named constant or else it refers to an ADT variant
+
+                        let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
+                        match res {
+                            Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
+                                // Named constants have to be equated with the value
+                                // being matched, so that's a read of the value being matched.
+                                //
+                                // FIXME: We don't actually  reads for ZSTs.
+                                needs_to_be_read = true;
+                            }
+                            _ => {
+                                // Otherwise, this is a struct/enum variant, and so it's
+                                // only a read if we need to read the discriminant.
+                                needs_to_be_read |= is_multivariant_adt(place.place.ty());
+                            }
+                        }
+                    }
+                    PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
+                        // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
+                        // against a multivariant enum or struct. In that case, we have to read
+                        // the discriminant. Otherwise this kind of pattern doesn't actually
+                        // read anything (we'll get invoked for the `...`, which may indeed
+                        // perform some reads).
+
+                        let place_ty = place.place.ty();
+                        needs_to_be_read |= is_multivariant_adt(place_ty);
+                    }
+                    PatKind::Lit(_) | PatKind::Range(..) => {
+                        // If the PatKind is a Lit or a Range then we want
+                        // to borrow discr.
+                        needs_to_be_read = true;
+                    }
+                    PatKind::Or(_)
+                    | PatKind::Box(_)
+                    | PatKind::Slice(..)
+                    | PatKind::Ref(..)
+                    | PatKind::Wild => {
+                        // If the PatKind is Or, Box, Slice or Ref, the decision is made later
+                        // as these patterns contains subpatterns
+                        // If the PatKind is Wild, the decision is made based on the other patterns being
+                        // examined
+                    }
+                }
+            }));
+        }
+
+        if needs_to_be_read {
+            self.borrow_expr(discr, ty::ImmBorrow);
+        } else {
+            let closure_def_id = match discr_place.place.base {
+                PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
+                _ => None,
+            };
+
+            self.delegate.fake_read(
+                &discr_place,
+                FakeReadCause::ForMatchedPlace(closure_def_id),
+                discr_place.hir_id,
+            );
+
+            // We always want to walk the discriminant. We want to make sure, for instance,
+            // that the discriminant has been initialized.
+            self.walk_expr(discr);
+        }
+    }
+
+    fn walk_local<F>(
+        &mut self,
+        expr: &hir::Expr<'_>,
+        pat: &hir::Pat<'_>,
+        els: Option<&hir::Block<'_>>,
+        mut f: F,
+    ) where
         F: FnMut(&mut Self),
     {
         self.walk_expr(expr);
         let expr_place = return_if_err!(self.mc.cat_expr(expr));
         f(self);
+        if let Some(els) = els {
+            // borrowing because we need to test the descriminant
+            self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter());
+            self.walk_block(els)
+        }
         self.walk_irrefutable_pat(&expr_place, &pat);
     }
 
@@ -667,7 +691,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
         return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
             if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
-                debug!("walk_pat: binding place={:?} pat={:?}", place, pat,);
+                debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
                 if let Some(bm) =
                     mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
                 {
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 63c83ddb6f7cf..8a37fadc56f4c 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1856,7 +1856,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 #[lang = "unsafe_cell"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(transparent)]
-#[repr(no_niche)] // rust-lang/rust#68303.
 pub struct UnsafeCell<T: ?Sized> {
     value: T,
 }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index bd256cec8a147..f24a7ab61ae89 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -191,7 +191,6 @@
 #![feature(never_type)]
 #![feature(no_core)]
 #![feature(no_coverage)] // rust-lang/rust#84605
-#![feature(no_niche)] // rust-lang/rust#68303
 #![feature(platform_intrinsics)]
 #![feature(prelude_import)]
 #![feature(repr_simd)]
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 316554808c201..db2ad953f6aa0 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -624,7 +624,7 @@ impl FromWithTcx<clean::VariantStruct> for Struct {
         let clean::VariantStruct { struct_type, fields } = struct_;
         Struct {
             struct_type: from_ctor_kind(struct_type),
-            generics: Default::default(),
+            generics: Generics { params: vec![], where_predicates: vec![] },
             fields_stripped,
             fields: ids(fields, tcx),
             impls: Vec::new(),
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index eb2c8e5bae1c4..1168a89a8b2bf 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -14,7 +14,7 @@ pub const FORMAT_VERSION: u32 = 15;
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
 /// tools to find or link to them.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Crate {
     /// The id of the root [`Module`] item of the local crate.
     pub root: Id,
@@ -34,7 +34,7 @@ pub struct Crate {
     pub format_version: u32,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ExternalCrate {
     pub name: String,
     pub html_root_url: Option<String>,
@@ -44,7 +44,7 @@ pub struct ExternalCrate {
 /// information. This struct should contain enough to generate a link/reference to the item in
 /// question, or can be used by a tool that takes the json output of multiple crates to find
 /// the actual item definition with all the relevant info.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ItemSummary {
     /// Can be used to look up the name and html_root_url of the crate this item came from in the
     /// `external_crates` map.
@@ -56,7 +56,7 @@ pub struct ItemSummary {
     pub kind: ItemKind,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Item {
     /// The unique identifier of this item. Can be used to find this item in various mappings.
     pub id: Id,
@@ -83,7 +83,7 @@ pub struct Item {
     pub inner: ItemEnum,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Span {
     /// The path to the source file for this span relative to the path `rustdoc` was invoked with.
     pub filename: PathBuf,
@@ -93,13 +93,13 @@ pub struct Span {
     pub end: (usize, usize),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Deprecation {
     pub since: Option<String>,
     pub note: Option<String>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Visibility {
     Public,
@@ -115,7 +115,7 @@ pub enum Visibility {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArgs {
     /// <'a, 32, B: Copy, C = u32>
@@ -124,7 +124,7 @@ pub enum GenericArgs {
     Parenthesized { inputs: Vec<Type>, output: Option<Type> },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArg {
     Lifetime(String),
@@ -133,7 +133,7 @@ pub enum GenericArg {
     Infer,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Constant {
     #[serde(rename = "type")]
     pub type_: Type,
@@ -142,14 +142,14 @@ pub struct Constant {
     pub is_literal: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TypeBinding {
     pub name: String,
     pub args: GenericArgs,
     pub binding: TypeBindingKind,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
     Equality(Term),
@@ -159,7 +159,7 @@ pub enum TypeBindingKind {
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Id(pub String);
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum ItemKind {
     Module,
@@ -189,7 +189,7 @@ pub enum ItemKind {
     Keyword,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(tag = "kind", content = "inner", rename_all = "snake_case")]
 pub enum ItemEnum {
     Module(Module),
@@ -241,13 +241,13 @@ pub enum ItemEnum {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Module {
     pub is_crate: bool,
     pub items: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Union {
     pub generics: Generics,
     pub fields_stripped: bool,
@@ -255,7 +255,7 @@ pub struct Union {
     pub impls: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Struct {
     pub struct_type: StructType,
     pub generics: Generics,
@@ -264,7 +264,7 @@ pub struct Struct {
     pub impls: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Enum {
     pub generics: Generics,
     pub variants_stripped: bool,
@@ -272,7 +272,7 @@ pub struct Enum {
     pub impls: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "variant_kind", content = "variant_inner")]
 pub enum Variant {
@@ -281,7 +281,7 @@ pub enum Variant {
     Struct(Vec<Id>),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum StructType {
     Plain,
@@ -289,7 +289,7 @@ pub enum StructType {
     Unit,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Header {
     #[serde(rename = "const")]
     pub const_: bool,
@@ -300,7 +300,7 @@ pub struct Header {
     pub abi: Abi,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Abi {
     // We only have a concrete listing here for stable ABI's because their are so many
     // See rustc_ast_passes::feature_gate::PostExpansionVisitor::check_abi for the list
@@ -316,14 +316,14 @@ pub enum Abi {
     Other(String),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Function {
     pub decl: FnDecl,
     pub generics: Generics,
     pub header: Header,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Method {
     pub decl: FnDecl,
     pub generics: Generics,
@@ -331,19 +331,19 @@ pub struct Method {
     pub has_body: bool,
 }
 
-#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Generics {
     pub params: Vec<GenericParamDef>,
     pub where_predicates: Vec<WherePredicate>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct GenericParamDef {
     pub name: String,
     pub kind: GenericParamDefKind,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericParamDefKind {
     Lifetime {
@@ -384,7 +384,7 @@ pub enum GenericParamDefKind {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum WherePredicate {
     BoundPredicate {
@@ -410,7 +410,7 @@ pub enum WherePredicate {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericBound {
     TraitBound {
@@ -429,7 +429,7 @@ pub enum GenericBound {
     Outlives(String),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum TraitBoundModifier {
     None,
@@ -437,14 +437,14 @@ pub enum TraitBoundModifier {
     MaybeConst,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Term {
     Type(Type),
     Constant(Constant),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
 pub enum Type {
@@ -498,7 +498,7 @@ pub enum Type {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct FunctionPointer {
     pub decl: FnDecl,
     /// Used for Higher-Rank Trait Bounds (HRTBs)
@@ -512,14 +512,14 @@ pub struct FunctionPointer {
     pub header: Header,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct FnDecl {
     pub inputs: Vec<(String, Type)>,
     pub output: Option<Type>,
     pub c_variadic: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Trait {
     pub is_auto: bool,
     pub is_unsafe: bool,
@@ -529,13 +529,13 @@ pub struct Trait {
     pub implementations: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TraitAlias {
     pub generics: Generics,
     pub params: Vec<GenericBound>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Impl {
     pub is_unsafe: bool,
     pub generics: Generics,
@@ -550,7 +550,7 @@ pub struct Impl {
     pub blanket_impl: Option<Type>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub struct Import {
     /// The full path being imported.
@@ -564,37 +564,37 @@ pub struct Import {
     pub glob: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ProcMacro {
     pub kind: MacroKind,
     pub helpers: Vec<String>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum MacroKind {
     /// A bang macro `foo!()`.
     Bang,
     /// An attribute macro `#[foo]`.
     Attr,
-    /// A derive macro `#[derive(Foo)]`
+    /// A derive macro `#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]`
     Derive,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Typedef {
     #[serde(rename = "type")]
     pub type_: Type,
     pub generics: Generics,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct OpaqueTy {
     pub bounds: Vec<GenericBound>,
     pub generics: Generics,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Static {
     #[serde(rename = "type")]
     pub type_: Type,
diff --git a/src/test/ui/async-await/async-await-let-else.rs b/src/test/ui/async-await/async-await-let-else.rs
new file mode 100644
index 0000000000000..7ea07ae9add1b
--- /dev/null
+++ b/src/test/ui/async-await/async-await-let-else.rs
@@ -0,0 +1,53 @@
+// edition:2021
+#![feature(let_else)]
+use std::rc::Rc;
+
+async fn foo(x: Option<bool>) {
+    let Some(_) = x else {
+        let r = Rc::new(());
+        bar().await
+    };
+}
+
+async fn bar() -> ! {
+    panic!()
+}
+
+fn is_send<T: Send>(_: T) {}
+
+async fn foo2(x: Option<bool>) {
+    let Some(_) = x else {
+        bar2(Rc::new(())).await
+    };
+}
+
+async fn bar2<T>(_: T) -> ! {
+    panic!()
+}
+
+async fn foo3(x: Option<bool>) {
+    let Some(_) = x else {
+        (Rc::new(()), bar().await);
+        return;
+    };
+}
+
+async fn foo4(x: Option<bool>) {
+    let Some(_) = x else {
+        let r = Rc::new(());
+        bar().await;
+        println!("{:?}", r);
+        return;
+    };
+}
+
+fn main() {
+    is_send(foo(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+    is_send(foo2(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+    is_send(foo3(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+    is_send(foo4(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+}
diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr
new file mode 100644
index 0000000000000..4d23e27c426b2
--- /dev/null
+++ b/src/test/ui/async-await/async-await-let-else.stderr
@@ -0,0 +1,94 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:45:13
+   |
+LL |     is_send(foo(Some(true)));
+   |             ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:8:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:47:13
+   |
+LL |     is_send(foo2(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:20:26
+   |
+LL |         bar2(Rc::new(())).await
+   |              ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
+   |              |
+   |              has type `Rc<()>` which is not `Send`
+LL |     };
+   |      - `Rc::new(())` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:49:13
+   |
+LL |     is_send(foo3(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:30:28
+   |
+LL |         (Rc::new(()), bar().await);
+   |          -----------       ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
+   |          |
+   |          has type `Rc<()>` which is not `Send`
+note: `Rc::new(())` is later dropped here
+  --> $DIR/async-await-let-else.rs:30:35
+   |
+LL |         (Rc::new(()), bar().await);
+   |                                   ^
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:51:13
+   |
+LL |     is_send(foo4(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:38:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await;
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+...
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs b/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs
new file mode 100644
index 0000000000000..0bcb997d96cde
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs
@@ -0,0 +1,8 @@
+fn bug<'a>()
+where
+    [(); { //~ ERROR mismatched types
+        let _: &'a (); //~ ERROR a non-static lifetime is not allowed in a `const`
+    }]:
+{}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr
new file mode 100644
index 0000000000000..e7673df0a025c
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr
@@ -0,0 +1,22 @@
+error[E0658]: a non-static lifetime is not allowed in a `const`
+  --> $DIR/issue-74713.rs:4:17
+   |
+LL |         let _: &'a ();
+   |                 ^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+  --> $DIR/issue-74713.rs:3:10
+   |
+LL |       [(); {
+   |  __________^
+LL | |         let _: &'a ();
+LL | |     }]:
+   | |_____^ expected `usize`, found `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs
index 4ca3f7a1aad94..fce101d7bb173 100644
--- a/src/test/ui/layout/unsafe-cell-hides-niche.rs
+++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs
@@ -3,30 +3,79 @@
 // test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same
 // size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes).
 
-// run-pass
+// check-pass
+// compile-flags: --crate-type=lib
 
-#![feature(no_niche)]
+#![feature(repr_simd)]
 
-use std::cell::UnsafeCell;
+use std::cell::{UnsafeCell, RefCell, Cell};
 use std::mem::size_of;
 use std::num::NonZeroU32 as N32;
+use std::sync::{Mutex, RwLock};
 
 struct Wrapper<T>(T);
 
 #[repr(transparent)]
 struct Transparent<T>(T);
 
-#[repr(no_niche)]
-struct NoNiche<T>(T);
+struct NoNiche<T>(UnsafeCell<T>);
 
-fn main() {
-    assert_eq!(size_of::<Option<Wrapper<u32>>>(),     8);
-    assert_eq!(size_of::<Option<Wrapper<N32>>>(),     4);
-    assert_eq!(size_of::<Option<Transparent<u32>>>(), 8);
-    assert_eq!(size_of::<Option<Transparent<N32>>>(), 4);
-    assert_eq!(size_of::<Option<NoNiche<u32>>>(),     8);
-    assert_eq!(size_of::<Option<NoNiche<N32>>>(),     8);
+struct Size<const S: usize>;
 
-    assert_eq!(size_of::<Option<UnsafeCell<u32>>>(),  8);
-    assert_eq!(size_of::<Option<UnsafeCell<N32>>>(),  8);
+macro_rules! check_sizes {
+    (check_one_specific_size: $ty:ty, $size:expr) => {
+        const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>;
+    };
+    // Any tests run on `UnsafeCell` must be the same for `Cell`
+    (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => {
+        check_sizes!(Cell<$ty>: $size => $optioned_size);
+        check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size);
+    };
+    ($ty:ty: $size:expr => $optioned_size:expr) => {
+        check_sizes!(@actual_check: $ty: $size => $optioned_size);
+    };
+    // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish
+    // it from other branches and not accidentally match any.
+    (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => {
+        check_sizes!(check_one_specific_size: $ty, $size);
+        check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size);
+        check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty);
+    };
+    // only check that there is no niche (size goes up when wrapped in an option),
+    // don't check actual sizes
+    ($ty:ty) => {
+        check_sizes!(check_no_niche_opt: true, $ty);
+    };
+    (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => {
+        const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::<Option<$ty>>()); };
+    };
 }
+
+const PTR_SIZE: usize = std::mem::size_of::<*const ()>();
+
+check_sizes!(Wrapper<u32>:     4 => 8);
+check_sizes!(Wrapper<N32>:     4 => 4); // (✓ niche opt)
+check_sizes!(Transparent<u32>: 4 => 8);
+check_sizes!(Transparent<N32>: 4 => 4); // (✓ niche opt)
+check_sizes!(NoNiche<u32>:     4 => 8);
+check_sizes!(NoNiche<N32>:     4 => 8);
+
+check_sizes!(UnsafeCell<u32>:  4 => 8);
+check_sizes!(UnsafeCell<N32>:  4 => 8);
+
+check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2);
+check_sizes!(   RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+check_sizes!(RwLock<&()>);
+check_sizes!(Mutex<&()>);
+
+check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3);
+check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+trait Trait {}
+check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+#[repr(simd)]
+pub struct Vec4<T>([T; 4]);
+
+check_sizes!(UnsafeCell<Vec4<N32>>: 16 => 32);
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
index fdec7e7f6a753..065787cab08ff 100644
--- a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37
    |
 LL |     let Some(n): &mut Option<i32> = &&Some(5i32) else { return };
-   |                                     ^^^^^^^^^^^^ types differ in mutability
+   |                  ----------------   ^^^^^^^^^^^^ types differ in mutability
+   |                  |
+   |                  expected due to this
    |
    = note: expected mutable reference `&mut Option<i32>`
                       found reference `&&Option<i32>`
@@ -11,7 +13,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37
    |
 LL |     let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return };
-   |                                     ^^^^^^^^^^^^^^^^ types differ in mutability
+   |                  ----------------   ^^^^^^^^^^^^^^^^ types differ in mutability
+   |                  |
+   |                  expected due to this
    |
    = note: expected mutable reference `&mut Option<i32>`
                       found reference `&&mut Option<i32>`
diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr
index b3da412ec280e..3d647a4c05d86 100644
--- a/src/test/ui/let-else/let-else-check.stderr
+++ b/src/test/ui/let-else/let-else-check.stderr
@@ -1,8 +1,8 @@
 error: unused variable: `x`
-  --> $DIR/let-else-check.rs:18:9
+  --> $DIR/let-else-check.rs:14:13
    |
-LL |     let x = 1;
-   |         ^ help: if this is intentional, prefix it with an underscore: `_x`
+LL |         let x = 1;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_x`
    |
 note: the lint level is defined here
   --> $DIR/let-else-check.rs:3:9
@@ -11,10 +11,10 @@ LL | #![deny(unused_variables)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unused variable: `x`
-  --> $DIR/let-else-check.rs:14:13
+  --> $DIR/let-else-check.rs:18:9
    |
-LL |         let x = 1;
-   |             ^ help: if this is intentional, prefix it with an underscore: `_x`
+LL |     let x = 1;
+   |         ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/let-else/let-else-non-diverging.stderr b/src/test/ui/let-else/let-else-non-diverging.stderr
index b961b16b6f6ef..05e45f689890d 100644
--- a/src/test/ui/let-else/let-else-non-diverging.stderr
+++ b/src/test/ui/let-else/let-else-non-diverging.stderr
@@ -1,8 +1,11 @@
 error[E0308]: `else` clause of `let...else` does not diverge
-  --> $DIR/let-else-non-diverging.rs:12:32
+  --> $DIR/let-else-non-diverging.rs:4:32
    |
-LL |     let Some(x) = Some(1) else { Some(2) };
-   |                                ^^^^^^^^^^^ expected `!`, found enum `Option`
+LL |       let Some(x) = Some(1) else {
+   |  ________________________________^
+LL | |         Some(2)
+LL | |     };
+   | |_____^ expected `!`, found enum `Option`
    |
    = note: expected type `!`
               found enum `Option<{integer}>`
@@ -26,13 +29,10 @@ LL | |     };
    = help: ...or use `match` instead of `let...else`
 
 error[E0308]: `else` clause of `let...else` does not diverge
-  --> $DIR/let-else-non-diverging.rs:4:32
+  --> $DIR/let-else-non-diverging.rs:12:32
    |
-LL |       let Some(x) = Some(1) else {
-   |  ________________________________^
-LL | |         Some(2)
-LL | |     };
-   | |_____^ expected `!`, found enum `Option`
+LL |     let Some(x) = Some(1) else { Some(2) };
+   |                                ^^^^^^^^^^^ expected `!`, found enum `Option`
    |
    = note: expected type `!`
               found enum `Option<{integer}>`
diff --git a/src/test/ui/let-else/let-else-ref-bindings.stderr b/src/test/ui/let-else/let-else-ref-bindings.stderr
index 650f4ec5e779f..56b9e073330a6 100644
--- a/src/test/ui/let-else/let-else-ref-bindings.stderr
+++ b/src/test/ui/let-else/let-else-ref-bindings.stderr
@@ -20,7 +20,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:24:34
    |
 LL |     let Some(a): Option<&[u8]> = some else { return };
-   |                                  ^^^^ expected `&[u8]`, found struct `Vec`
+   |                  -------------   ^^^^ expected `&[u8]`, found struct `Vec`
+   |                  |
+   |                  expected due to this
    |
    = note: expected enum `Option<&[u8]>`
               found enum `Option<Vec<u8>>`
@@ -29,7 +31,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:27:34
    |
 LL |     let Some(a): Option<&[u8]> = &some else { return };
-   |                                  ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+   |                  -------------   ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+   |                  |
+   |                  expected due to this
    |
    = note:   expected enum `Option<&[u8]>`
            found reference `&Option<Vec<u8>>`
@@ -56,7 +60,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:52:38
    |
 LL |     let Some(a): Option<&mut [u8]> = some else { return };
-   |                                      ^^^^ expected `&mut [u8]`, found struct `Vec`
+   |                  -----------------   ^^^^ expected `&mut [u8]`, found struct `Vec`
+   |                  |
+   |                  expected due to this
    |
    = note: expected enum `Option<&mut [u8]>`
               found enum `Option<Vec<u8>>`
@@ -65,7 +71,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:55:38
    |
 LL |     let Some(a): Option<&mut [u8]> = &mut some else { return };
-   |                                      ^^^^^^^^^ expected enum `Option`, found mutable reference
+   |                  -----------------   ^^^^^^^^^ expected enum `Option`, found mutable reference
+   |                  |
+   |                  expected due to this
    |
    = note:           expected enum `Option<&mut [u8]>`
            found mutable reference `&mut Option<Vec<u8>>`
diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs
new file mode 100644
index 0000000000000..624c2ea37a70b
--- /dev/null
+++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![feature(let_else)]
+
+use std::sync::atomic::{AtomicU8, Ordering};
+
+static TRACKER: AtomicU8 = AtomicU8::new(0);
+
+#[derive(Default)]
+struct Droppy {
+    inner: u32,
+}
+
+impl Drop for Droppy {
+    fn drop(&mut self) {
+        TRACKER.store(1, Ordering::Release);
+        println!("I've been dropped");
+    }
+}
+
+fn main() {
+    assert_eq!(TRACKER.load(Ordering::Acquire), 0);
+    let 0 = Droppy::default().inner else { return };
+    assert_eq!(TRACKER.load(Ordering::Acquire), 1);
+    println!("Should have dropped 👆");
+}
diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs
index 2ce4dd56eab0d..809e0602671fe 100644
--- a/src/test/ui/lint/clashing-extern-fn.rs
+++ b/src/test/ui/lint/clashing-extern-fn.rs
@@ -1,7 +1,6 @@
 // check-pass
 // aux-build:external_extern_fn.rs
 #![crate_type = "lib"]
-#![feature(no_niche)]
 #![warn(clashing_extern_declarations)]
 
 mod redeclared_different_signature {
@@ -400,9 +399,8 @@ mod hidden_niche {
         #[repr(transparent)]
         struct Transparent { x: NonZeroUsize }
 
-        #[repr(no_niche)]
         #[repr(transparent)]
-        struct TransparentNoNiche { y: NonZeroUsize }
+        struct TransparentNoNiche { y: UnsafeCell<NonZeroUsize> }
 
         extern "C" {
             fn hidden_niche_transparent() -> Option<Transparent>;
diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr
index a856de322c8ca..4607f68499322 100644
--- a/src/test/ui/lint/clashing-extern-fn.stderr
+++ b/src/test/ui/lint/clashing-extern-fn.stderr
@@ -1,5 +1,5 @@
 warning: `clash` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:15:13
+  --> $DIR/clashing-extern-fn.rs:14:13
    |
 LL |             fn clash(x: u8);
    |             ---------------- `clash` previously declared here
@@ -8,7 +8,7 @@ LL |             fn clash(x: u64);
    |             ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
 note: the lint level is defined here
-  --> $DIR/clashing-extern-fn.rs:5:9
+  --> $DIR/clashing-extern-fn.rs:4:9
    |
 LL | #![warn(clashing_extern_declarations)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | #![warn(clashing_extern_declarations)]
               found `unsafe extern "C" fn(u64)`
 
 warning: `extern_link_name` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:53:9
+  --> $DIR/clashing-extern-fn.rs:52:9
    |
 LL | /     #[link_name = "extern_link_name"]
 LL | |     fn some_new_name(x: i16);
@@ -29,7 +29,7 @@ LL |           fn extern_link_name(x: u32);
               found `unsafe extern "C" fn(u32)`
 
 warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
-  --> $DIR/clashing-extern-fn.rs:56:9
+  --> $DIR/clashing-extern-fn.rs:55:9
    |
 LL |       fn some_other_new_name(x: i16);
    |       ------------------------------- `some_other_new_name` previously declared here
@@ -43,7 +43,7 @@ LL | |         fn some_other_extern_link_name(x: u32);
               found `unsafe extern "C" fn(u32)`
 
 warning: `other_both_names_different` redeclares `link_name_same` with a different signature
-  --> $DIR/clashing-extern-fn.rs:60:9
+  --> $DIR/clashing-extern-fn.rs:59:9
    |
 LL | /     #[link_name = "link_name_same"]
 LL | |     fn both_names_different(x: i16);
@@ -58,7 +58,7 @@ LL | |         fn other_both_names_different(x: u32);
               found `unsafe extern "C" fn(u32)`
 
 warning: `different_mod` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:73:9
+  --> $DIR/clashing-extern-fn.rs:72:9
    |
 LL |         fn different_mod(x: u8);
    |         ------------------------ `different_mod` previously declared here
@@ -70,7 +70,7 @@ LL |         fn different_mod(x: u64);
               found `unsafe extern "C" fn(u64)`
 
 warning: `variadic_decl` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:83:9
+  --> $DIR/clashing-extern-fn.rs:82:9
    |
 LL |     fn variadic_decl(x: u8, ...);
    |     ----------------------------- `variadic_decl` previously declared here
@@ -82,7 +82,7 @@ LL |         fn variadic_decl(x: u8);
               found `unsafe extern "C" fn(u8)`
 
 warning: `weigh_banana` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:143:13
+  --> $DIR/clashing-extern-fn.rs:142:13
    |
 LL |             fn weigh_banana(count: *const Banana) -> u64;
    |             --------------------------------------------- `weigh_banana` previously declared here
@@ -94,7 +94,7 @@ LL |             fn weigh_banana(count: *const Banana) -> u64;
               found `unsafe extern "C" fn(*const three::Banana) -> u64`
 
 warning: `draw_point` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:172:13
+  --> $DIR/clashing-extern-fn.rs:171:13
    |
 LL |             fn draw_point(p: Point);
    |             ------------------------ `draw_point` previously declared here
@@ -106,7 +106,7 @@ LL |             fn draw_point(p: Point);
               found `unsafe extern "C" fn(sameish_members::b::Point)`
 
 warning: `origin` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:198:13
+  --> $DIR/clashing-extern-fn.rs:197:13
    |
 LL |             fn origin() -> Point3;
    |             ---------------------- `origin` previously declared here
@@ -118,7 +118,7 @@ LL |             fn origin() -> Point3;
               found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
 
 warning: `transparent_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:221:13
+  --> $DIR/clashing-extern-fn.rs:220:13
    |
 LL |             fn transparent_incorrect() -> T;
    |             -------------------------------- `transparent_incorrect` previously declared here
@@ -130,7 +130,7 @@ LL |             fn transparent_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `missing_return_type` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:239:13
+  --> $DIR/clashing-extern-fn.rs:238:13
    |
 LL |             fn missing_return_type() -> usize;
    |             ---------------------------------- `missing_return_type` previously declared here
@@ -142,7 +142,7 @@ LL |             fn missing_return_type();
               found `unsafe extern "C" fn()`
 
 warning: `non_zero_usize` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:257:13
+  --> $DIR/clashing-extern-fn.rs:256:13
    |
 LL |             fn non_zero_usize() -> core::num::NonZeroUsize;
    |             ----------------------------------------------- `non_zero_usize` previously declared here
@@ -154,7 +154,7 @@ LL |             fn non_zero_usize() -> usize;
               found `unsafe extern "C" fn() -> usize`
 
 warning: `non_null_ptr` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:259:13
+  --> $DIR/clashing-extern-fn.rs:258:13
    |
 LL |             fn non_null_ptr() -> core::ptr::NonNull<usize>;
    |             ----------------------------------------------- `non_null_ptr` previously declared here
@@ -166,7 +166,7 @@ LL |             fn non_null_ptr() -> *const usize;
               found `unsafe extern "C" fn() -> *const usize`
 
 warning: `option_non_zero_usize_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:357:13
+  --> $DIR/clashing-extern-fn.rs:356:13
    |
 LL |             fn option_non_zero_usize_incorrect() -> usize;
    |             ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -178,7 +178,7 @@ LL |             fn option_non_zero_usize_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `option_non_null_ptr_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:359:13
+  --> $DIR/clashing-extern-fn.rs:358:13
    |
 LL |             fn option_non_null_ptr_incorrect() -> *const usize;
    |             --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@@ -190,7 +190,7 @@ LL |             fn option_non_null_ptr_incorrect() -> *const isize;
               found `unsafe extern "C" fn() -> *const isize`
 
 warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:410:13
+  --> $DIR/clashing-extern-fn.rs:408:13
    |
 LL |             fn hidden_niche_transparent_no_niche() -> usize;
    |             ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
@@ -202,7 +202,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
               found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
 
 warning: `hidden_niche_unsafe_cell` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:414:13
+  --> $DIR/clashing-extern-fn.rs:412:13
    |
 LL |             fn hidden_niche_unsafe_cell() -> usize;
    |             --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
@@ -214,7 +214,7 @@ LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize
               found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
 
 warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:410:55
+  --> $DIR/clashing-extern-fn.rs:408:55
    |
 LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
    |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -224,7 +224,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
    = note: enum has no representation hint
 
 warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:414:46
+  --> $DIR/clashing-extern-fn.rs:412:46
    |
 LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
diff --git a/src/test/ui/repr/feature-gate-no-niche.rs b/src/test/ui/repr/feature-gate-no-niche.rs
deleted file mode 100644
index 8872ee7119e4a..0000000000000
--- a/src/test/ui/repr/feature-gate-no-niche.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::num::NonZeroU8 as N8;
-use std::num::NonZeroU16 as N16;
-
-#[repr(no_niche)]
-pub struct Cloaked(N16);
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-#[repr(transparent, no_niche)]
-pub struct Shadowy(N16);
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-#[repr(no_niche)]
-pub enum Cloaked1 { _A(N16), }
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-#[repr(no_niche)]
-pub enum Cloaked2 { _A(N16), _B(u8, N8) }
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-fn main() { }
diff --git a/src/test/ui/repr/feature-gate-no-niche.stderr b/src/test/ui/repr/feature-gate-no-niche.stderr
deleted file mode 100644
index 34fd417cc99a2..0000000000000
--- a/src/test/ui/repr/feature-gate-no-niche.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:4:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:8:21
-   |
-LL | #[repr(transparent, no_niche)]
-   |                     ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:12:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:16:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs
deleted file mode 100644
index 870eda89c20d7..0000000000000
--- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-#![feature(no_niche)]
-
-use std::num::NonZeroU8 as N8;
-use std::num::NonZeroU16 as N16;
-
-#[repr(no_niche)]
-pub union Cloaked1 { _A: N16 }
-//~^^ ERROR attribute should be applied to a struct or enum [E0517]
-
-#[repr(no_niche)]
-pub union Cloaked2 { _A: N16, _B: (u8, N8) }
-//~^^ ERROR attribute should be applied to a struct or enum [E0517]
-
-fn main() { }
diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr
deleted file mode 100644
index 9af929d409473..0000000000000
--- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0517]: attribute should be applied to a struct or enum
-  --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-LL | pub union Cloaked1 { _A: N16 }
-   | ------------------------------ not a struct or enum
-
-error[E0517]: attribute should be applied to a struct or enum
-  --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) }
-   | -------------------------------------------- not a struct or enum
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0517`.
diff --git a/src/test/ui/repr/repr-no-niche.rs b/src/test/ui/repr/repr-no-niche.rs
deleted file mode 100644
index 2e6064aeb0074..0000000000000
--- a/src/test/ui/repr/repr-no-niche.rs
+++ /dev/null
@@ -1,327 +0,0 @@
-// run-pass
-
-// This file tests repr(no_niche), which causes an struct/enum to hide
-// any niche space that may exist in its internal state from the
-// context it appears in.
-
-// Here are the axes this test is seeking to cover:
-//
-// repr annotation:
-// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche)
-//
-// enum vs struct
-//
-// niche-type via type-parameter vs inline declaration
-
-#![feature(decl_macro)]
-#![feature(no_niche)]
-
-use std::mem::size_of;
-use std::num::{NonZeroU8, NonZeroU16};
-
-mod struct_inline {
-    use std::num::NonZeroU16 as N16;
-
-    #[derive(Debug)] pub struct Visible(N16);
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub struct Cloaked(N16);
-
-    #[repr(transparent)]
-    #[derive(Debug)] pub struct Transparent(N16);
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub struct Shadowy(N16);
-}
-
-mod struct_param {
-    #[derive(Debug)] pub struct Visible<T>(T);
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub struct Cloaked<T>(T);
-
-    #[repr(transparent)]
-    #[derive(Debug)] pub struct Transparent<T>(T);
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub struct Shadowy<T>(T);
-}
-
-mod enum_inline {
-    use crate::two_fifty_six_variant_enum;
-    use std::num::{NonZeroU8 as N8, NonZeroU16 as N16};
-
-    #[derive(Debug)] pub enum Visible1 { _A(N16), }
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub enum Cloaked1 { _A(N16), }
-
-    // (N.B.: transparent enums must be univariant)
-    #[repr(transparent)]
-    #[derive(Debug)] pub enum Transparent { _A(N16), }
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub enum Shadowy { _A(N16), }
-
-    // including multivariant enums for completeness. Payload and
-    // number of variants (i.e. discriminant size) have been chosen so
-    // that layout including discriminant is 4 bytes, with no space in
-    // padding to hide another discrimnant from the surrounding
-    // context.
-    //
-    // (Note that multivariant enums cannot usefully expose a niche in
-    // general; this test is relying on that.)
-    two_fifty_six_variant_enum!(Visible2, N8);
-
-    two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8);
-}
-
-mod enum_param {
-    use super::two_fifty_six_variant_enum;
-
-    #[derive(Debug)] pub enum Visible1<T> { _A(T), }
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub enum Cloaked1<T> { _A(T), }
-
-    // (N.B.: transparent enums must be univariant)
-    #[repr(transparent)]
-    #[derive(Debug)] pub enum Transparent<T> { _A(T), }
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub enum Shadowy<T> { _A(T), }
-
-    // including multivariant enums for completeness. Same notes apply
-    // here as above (assuming `T` is instantiated with `NonZeroU8`).
-    two_fifty_six_variant_enum!(Visible2<T>);
-
-    two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2<T>);
-}
-
-fn main() {
-    // sanity-checks
-    assert_eq!(size_of::<struct_inline::Visible>(),               2);
-    assert_eq!(size_of::<struct_inline::Cloaked>(),               2);
-    assert_eq!(size_of::<struct_inline::Transparent>(),           2);
-    assert_eq!(size_of::<struct_inline::Shadowy>(),               2);
-
-    assert_eq!(size_of::<struct_param::Visible<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<struct_param::Cloaked<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<struct_param::Transparent<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<struct_param::Shadowy<NonZeroU16>>(), 2);
-
-    assert_eq!(size_of::<enum_inline::Visible1>(),    2);
-    assert_eq!(size_of::<enum_inline::Cloaked1>(),    2);
-    assert_eq!(size_of::<enum_inline::Transparent>(), 2); // transparent enums are univariant
-    assert_eq!(size_of::<enum_inline::Shadowy>(),     2);
-    assert_eq!(size_of::<enum_inline::Visible2>(),    4);
-    assert_eq!(size_of::<enum_inline::Cloaked2>(),    4);
-
-    assert_eq!(size_of::<enum_param::Visible1<NonZeroU16>>(),    2);
-    assert_eq!(size_of::<enum_param::Cloaked1<NonZeroU16>>(),    2);
-    assert_eq!(size_of::<enum_param::Transparent<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<enum_param::Shadowy<NonZeroU16>>(),     2);
-    assert_eq!(size_of::<enum_param::Visible2<NonZeroU8>>(),     4);
-    assert_eq!(size_of::<enum_param::Cloaked2<NonZeroU8>>(),     4);
-
-    // now the actual tests of no_niche: how do inputs above compose
-    // with `Option` type constructor. The cases with a `_+2` are the
-    // ones where no_niche fires.
-    assert_eq!(size_of::<Option<struct_inline::Visible>>(),       2);
-    assert_eq!(size_of::<Option<struct_inline::Cloaked>>(),       2+2);
-    assert_eq!(size_of::<Option<struct_inline::Transparent>>(),   2);
-    assert_eq!(size_of::<Option<struct_inline::Shadowy>>(),       2+2);
-
-    assert_eq!(size_of::<Option<struct_param::Visible<NonZeroU16>>>(),     2);
-    assert_eq!(size_of::<Option<struct_param::Cloaked<NonZeroU16>>>(),     2+2);
-    assert_eq!(size_of::<Option<struct_param::Transparent<NonZeroU16>>>(), 2);
-    assert_eq!(size_of::<Option<struct_param::Shadowy<NonZeroU16>>>(),     2+2);
-
-    assert_eq!(size_of::<Option<enum_inline::Visible1>>(),    2);
-    assert_eq!(size_of::<Option<enum_inline::Cloaked1>>(),    2+2);
-    assert_eq!(size_of::<Option<enum_inline::Transparent>>(), 2);
-    assert_eq!(size_of::<Option<enum_inline::Shadowy>>(),     2+2);
-    // cannot use niche of multivariant payload
-    assert_eq!(size_of::<Option<enum_inline::Visible2>>(),    4+2);
-    assert_eq!(size_of::<Option<enum_inline::Cloaked2>>(),    4+2);
-
-    assert_eq!(size_of::<Option<enum_param::Visible1<NonZeroU16>>>(),    2);
-    assert_eq!(size_of::<Option<enum_param::Cloaked1<NonZeroU16>>>(),    2+2);
-    assert_eq!(size_of::<Option<enum_param::Transparent<NonZeroU16>>>(), 2);
-    assert_eq!(size_of::<Option<enum_param::Shadowy<NonZeroU16>>>(),     2+2);
-    // cannot use niche of multivariant payload
-    assert_eq!(size_of::<Option<enum_param::Visible2<NonZeroU8>>>(),    4+2);
-    assert_eq!(size_of::<Option<enum_param::Cloaked2<NonZeroU8>>>(),    4+2);
-}
-
-macro two_fifty_six_variant_enum {
-    ($(#[$attr:meta])* $name:ident<$param:ident>) => {
-        #[derive(Debug)] $(#[$attr])*
-        pub enum $name<$param> {
-            _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
-            _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
-            _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param),
-            _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param),
-
-            _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param),
-            _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param),
-            _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param),
-            _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param),
-
-            _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param),
-            _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param),
-            _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param),
-            _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param),
-
-            _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param),
-            _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param),
-            _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param),
-            _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param),
-
-            _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param),
-            _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param),
-            _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param),
-            _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param),
-
-            _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param),
-            _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param),
-            _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param),
-            _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param),
-
-            _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param),
-            _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param),
-            _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param),
-            _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param),
-
-            _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param),
-            _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param),
-            _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param),
-            _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param),
-
-            _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param),
-            _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param),
-            _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param),
-            _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param),
-
-            _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param),
-            _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param),
-            _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param),
-            _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param),
-
-            _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param),
-            _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param),
-            _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param),
-            _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param),
-
-            _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param),
-            _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param),
-            _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param),
-            _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param),
-
-            _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param),
-            _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param),
-            _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param),
-            _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param),
-
-            _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param),
-            _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param),
-            _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param),
-            _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param),
-
-            _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param),
-            _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param),
-            _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param),
-            _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param),
-
-            _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param),
-            _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param),
-            _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param),
-            _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param),
-        }
-    },
-
-    ($(#[$attr:meta])* $name:ident, $param:ty) => {
-        #[derive(Debug)] $(#[$attr])*
-        pub enum $name {
-            _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
-            _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
-            _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param),
-            _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param),
-
-            _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param),
-            _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param),
-            _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param),
-            _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param),
-
-            _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param),
-            _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param),
-            _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param),
-            _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param),
-
-            _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param),
-            _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param),
-            _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param),
-            _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param),
-
-            _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param),
-            _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param),
-            _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param),
-            _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param),
-
-            _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param),
-            _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param),
-            _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param),
-            _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param),
-
-            _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param),
-            _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param),
-            _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param),
-            _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param),
-
-            _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param),
-            _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param),
-            _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param),
-            _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param),
-
-            _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param),
-            _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param),
-            _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param),
-            _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param),
-
-            _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param),
-            _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param),
-            _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param),
-            _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param),
-
-            _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param),
-            _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param),
-            _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param),
-            _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param),
-
-            _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param),
-            _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param),
-            _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param),
-            _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param),
-
-            _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param),
-            _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param),
-            _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param),
-            _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param),
-
-            _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param),
-            _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param),
-            _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param),
-            _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param),
-
-            _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param),
-            _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param),
-            _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param),
-            _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param),
-
-            _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param),
-            _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param),
-            _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param),
-            _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param),
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index 45af6be2653f3..ca617859db49d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -11,7 +11,7 @@ use rustc_lint::LateContext;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
     let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
         ([stmt, stmts @ ..], expr) => {
-            if let StmtKind::Local(&Local { init: Some(e), .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
+            if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
                 (e, !stmts.is_empty() || expr.is_some())
             } else {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index b2a873ef5823c..3077b999f4ee4 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1041,7 +1041,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
     }
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
-        self.infallible_destructuring_match_linted |= infallible_destructuring_match::check(cx, local);
+        self.infallible_destructuring_match_linted |=
+            local.els.is_none() && infallible_destructuring_match::check(cx, local);
     }
 
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 6598413c77ecc..819646bb6780e 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -92,6 +92,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
         if_chain! {
             if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id);
             if let Some(init) = local.init;
+            if local.els.is_none();
             if !local.pat.span.from_expansion();
             if has_no_effect(cx, init);
             if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index a1ef32ae60805..6bce5fbd4c1fe 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -148,7 +148,7 @@ fn is_value_unfrozen_raw<'tcx>(
         match val.ty().kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
-            ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true,
+            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
             ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
                 let val = cx.tcx.destructure_mir_constant(cx.param_env, val);
                 val.fields.iter().any(|field| inner(cx, *field))
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 5ae04947b82d0..1d9a2abf7066c 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -10,7 +10,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 
@@ -203,9 +202,7 @@ fn check_final_expr<'tcx>(
                 check_block_return(cx, ifblock);
             }
             if let Some(else_clause) = else_clause_opt {
-                if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) {
-                    check_final_expr(cx, else_clause, None, RetReplacement::Empty);
-                }
+                check_final_expr(cx, else_clause, None, RetReplacement::Empty);
             }
         },
         // a match expr, check all arms
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 793e3cc58c21d..942f14ddd3d51 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -102,7 +102,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> {
 impl HirEqInterExpr<'_, '_, '_> {
     pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&StmtKind::Local(l), &StmtKind::Local(r)) => {
+            (&StmtKind::Local(l, ), &StmtKind::Local(r, )) => {
                 // This additional check ensures that the type of the locals are equivalent even if the init
                 // expression or type have some inferred parts.
                 if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
@@ -117,6 +117,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 // these only get added if the init and type is equal.
                 both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                     && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
+                    && both(&l.els, &r.els, |l, r| self.eq_block(l, r))
                     && self.eq_pat(l.pat, r.pat)
             },
             (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
@@ -921,11 +922,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         std::mem::discriminant(&b.kind).hash(&mut self.s);
 
         match &b.kind {
-            StmtKind::Local(local) => {
+            StmtKind::Local(local, ) => {
                 self.hash_pat(local.pat);
                 if let Some(init) = local.init {
                     self.hash_expr(init);
                 }
+                if let Some(els) = local.els {
+                    self.hash_block(els);
+                }
             },
             StmtKind::Item(..) => {},
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
diff --git a/triagebot.toml b/triagebot.toml
index ba9ed20cc64a2..3842da566a91d 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -165,6 +165,19 @@ exclude_labels = [
     "T-*",
 ]
 
+[autolabel."A-bootstrap"]
+trigger_files = [
+    "x.py",
+    "src/bootstrap",
+    "src/tools/rust-installer",
+]
+
+[autolabel."T-infra"]
+trigger_files = [
+    "src/ci",
+    "src/tools/bump-stage0",
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"
@@ -279,6 +292,9 @@ Examples of `T-libs-api` changes:
 * Changing observable runtime behavior of library APIs
 """
 
+[mentions."library/proc_macro/src/bridge"]
+cc = ["@rust-lang/wg-rls-2"]
+
 [mentions."src/librustdoc/clean/types.rs"]
 cc = ["@camelid"]