Rollup merge of #122401 - ChrisDenton:check-tier1, r=Mark-Simulacrum

Check library crates for all tier 1 targets in PR CI

Let's try checking all tier 1 targets. Shouldn't take much time.

Not sure if this is the right place to put it or not but let's see if it works first.
diff --git a/Cargo.lock b/Cargo.lock
index 16aed3d..927e93f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4400,6 +4400,7 @@
  "rustc_lexer",
  "rustc_macros",
  "rustc_middle",
+ "rustc_privacy",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -6279,12 +6280,14 @@
 
 [[package]]
 name = "windows-bindgen"
-version = "0.52.0"
+version = "0.55.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "970efb0b6849eb8a87a898f586af7cc167567b070014c7434514c0bde0ca341c"
+checksum = "073ff8a486ebad239d557809d2cd5fe5e04ee1de29e09c6cd83fb0bae19b8a4c"
 dependencies = [
  "proc-macro2",
  "rayon",
+ "serde",
+ "serde_json",
  "syn 2.0.52",
  "windows-metadata",
 ]
@@ -6300,9 +6303,9 @@
 
 [[package]]
 name = "windows-metadata"
-version = "0.52.0"
+version = "0.55.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "218fd59201e26acdbb894fa2b302d1de84bf3eec7d0eb894ac8e9c5a854ee4ef"
+checksum = "b602635050172a1fc57a35040d4d225baefc6098fefd97094919921d95961a7d"
 
 [[package]]
 name = "windows-sys"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d522c28..d0e8b86 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1021,7 +1021,7 @@
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum StmtKind {
     /// A local (let) binding.
-    Local(P<Local>),
+    Let(P<Local>),
     /// An item definition.
     Item(P<Item>),
     /// Expr without trailing semi-colon.
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 4dc9c30..a048622 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -182,7 +182,7 @@
 impl HasTokens for StmtKind {
     fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         match self {
-            StmtKind::Local(local) => local.tokens.as_ref(),
+            StmtKind::Let(local) => local.tokens.as_ref(),
             StmtKind::Item(item) => item.tokens(),
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
             StmtKind::Empty => return None,
@@ -191,7 +191,7 @@
     }
     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
         match self {
-            StmtKind::Local(local) => Some(&mut local.tokens),
+            StmtKind::Let(local) => Some(&mut local.tokens),
             StmtKind::Item(item) => item.tokens_mut(),
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
             StmtKind::Empty => return None,
@@ -355,7 +355,7 @@
 
     fn attrs(&self) -> &[Attribute] {
         match self {
-            StmtKind::Local(local) => &local.attrs,
+            StmtKind::Let(local) => &local.attrs,
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
             StmtKind::Item(item) => item.attrs(),
             StmtKind::Empty => &[],
@@ -365,7 +365,7 @@
 
     fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         match self {
-            StmtKind::Local(local) => f(&mut local.attrs),
+            StmtKind::Let(local) => f(&mut local.attrs),
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
             StmtKind::Item(item) => item.visit_attrs(f),
             StmtKind::Empty => {}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 9ec92c9..83468c5 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1567,7 +1567,7 @@
     vis: &mut T,
 ) -> SmallVec<[StmtKind; 1]> {
     match kind {
-        StmtKind::Local(mut local) => smallvec![StmtKind::Local({
+        StmtKind::Let(mut local) => smallvec![StmtKind::Let({
             vis.visit_local(&mut local);
             local
         })],
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 5ed2762..a17c770 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -276,8 +276,10 @@
         Some(suffix) => LitKind::Float(
             symbol,
             ast::LitFloatType::Suffixed(match suffix {
+                sym::f16 => ast::FloatTy::F16,
                 sym::f32 => ast::FloatTy::F32,
                 sym::f64 => ast::FloatTy::F64,
+                sym::f128 => ast::FloatTy::F128,
                 _ => return Err(LitError::InvalidFloatSuffix(suffix)),
             }),
         ),
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 7296e29..d75ff45 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -787,7 +787,7 @@
 
 pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
     match &statement.kind {
-        StmtKind::Local(local) => try_visit!(visitor.visit_local(local)),
+        StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
         StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
         StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)),
         StmtKind::Empty => {}
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 865a56b..11a66fe 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -32,11 +32,11 @@
         let mut expr = None;
         while let [s, tail @ ..] = ast_stmts {
             match &s.kind {
-                StmtKind::Local(local) => {
+                StmtKind::Let(local) => {
                     let hir_id = self.lower_node_id(s.id);
                     let local = self.lower_local(local);
                     self.alias_attrs(hir_id, local.hir_id);
-                    let kind = hir::StmtKind::Local(local);
+                    let kind = hir::StmtKind::Let(local);
                     let span = self.lower_span(s.span);
                     stmts.push(hir::Stmt { hir_id, kind, span });
                 }
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 11aa6b2..793fe9c 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -55,6 +55,7 @@
         OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
         OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
         OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
+        OwnerNode::AssocOpaqueTy(..) => unreachable!(),
     };
 
     for (local_id, node) in collector.nodes.iter_enumerated() {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 94e1e06..6a7ee93 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -642,23 +642,8 @@
         let bodies = SortedMap::from_presorted_elements(bodies);
 
         // Don't hash unless necessary, because it's expensive.
-        let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
-            self.tcx.with_stable_hashing_context(|mut hcx| {
-                let mut stable_hasher = StableHasher::new();
-                node.hash_stable(&mut hcx, &mut stable_hasher);
-                // Bodies are stored out of line, so we need to pull them explicitly in the hash.
-                bodies.hash_stable(&mut hcx, &mut stable_hasher);
-                let h1 = stable_hasher.finish();
-
-                let mut stable_hasher = StableHasher::new();
-                attrs.hash_stable(&mut hcx, &mut stable_hasher);
-                let h2 = stable_hasher.finish();
-
-                (Some(h1), Some(h2))
-            })
-        } else {
-            (None, None)
-        };
+        let (opt_hash_including_bodies, attrs_hash) =
+            self.tcx.hash_owner_nodes(node, &bodies, &attrs);
         let num_nodes = self.item_local_id_counter.as_usize();
         let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
         let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
@@ -2356,7 +2341,7 @@
             span: self.lower_span(span),
             ty: None,
         };
-        self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
+        self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
     }
 
     fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 2e14238..4db8ffd 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,7 +1,7 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
-use rustc_ast::{PatKind, RangeEnd};
+use rustc_ast::{token, PatKind, RangeEnd};
 use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
 use rustc_session::Session;
@@ -378,6 +378,17 @@
             ast::ExprKind::TryBlock(_) => {
                 gate!(&self, try_blocks, e.span, "`try` expression is experimental");
             }
+            ast::ExprKind::Lit(token::Lit { kind: token::LitKind::Float, suffix, .. }) => {
+                match suffix {
+                    Some(sym::f16) => {
+                        gate!(&self, f16, e.span, "the type `f16` is unstable")
+                    }
+                    Some(sym::f128) => {
+                        gate!(&self, f128, e.span, "the type `f128` is unstable")
+                    }
+                    _ => (),
+                }
+            }
             _ => {}
         }
         visit::walk_expr(self, e)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index e5d7b84..c50878e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1212,7 +1212,7 @@
     fn print_stmt(&mut self, st: &ast::Stmt) {
         self.maybe_print_comment(st.span.lo());
         match &st.kind {
-            ast::StmtKind::Local(loc) => {
+            ast::StmtKind::Let(loc) => {
                 self.print_outer_attributes(&loc.attrs);
                 self.space_if_not_bol();
                 self.ibox(INDENT_UNIT);
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index bf14d5e..f2ca509 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -16,6 +16,9 @@
 borrowck_borrow_due_to_use_coroutine =
     borrow occurs due to use in coroutine
 
+borrowck_calling_operator_moves =
+    calling this operator moves the value
+
 borrowck_calling_operator_moves_lhs =
     calling this operator moves the left-hand side
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 0776f45..f81c74f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -12,7 +12,6 @@
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{CoroutineDesugaring, PatField};
 use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
-use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
@@ -21,16 +20,21 @@
     PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
     VarBindingForm,
 };
-use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt};
+use rustc_middle::ty::{
+    self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
+    TypeSuperVisitable, TypeVisitor,
+};
 use rustc_middle::util::CallKind;
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
+use rustc_span::def_id::DefId;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
-use rustc_trait_selection::traits::ObligationCtxt;
+use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
 use std::iter;
 
 use crate::borrow_set::TwoPhaseActivation;
@@ -39,7 +43,7 @@
 use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
-    InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
+    InitializationRequiringAction, MirBorrowckCtxt, WriteKind,
 };
 
 use super::{
@@ -114,7 +118,7 @@
             self.buffer_error(err);
         } else {
             if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
-                if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
+                if used_place.is_prefix_of(*reported_place) {
                     debug!(
                         "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
                         move_out_indices
@@ -283,7 +287,8 @@
                 // something that already has `Fn`-like bounds (or is a closure), so we can't
                 // restrict anyways.
             } else {
-                self.suggest_adding_copy_bounds(&mut err, ty, span);
+                let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
+                self.suggest_adding_bounds(&mut err, ty, copy_did, span);
             }
 
             if needs_note {
@@ -422,8 +427,7 @@
                     (None, &[][..], 0)
                 };
                 if let Some(def_id) = def_id
-                    && let node =
-                        self.infcx.tcx.hir_node(self.infcx.tcx.local_def_id_to_hir_id(def_id))
+                    && let node = self.infcx.tcx.hir_node_by_def_id(def_id)
                     && let Some(fn_sig) = node.fn_sig()
                     && let Some(ident) = node.ident()
                     && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
@@ -616,7 +620,7 @@
 
                     // FIXME: We make sure that this is a normal top-level binding,
                     // but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern
-                    if let hir::StmtKind::Local(hir::Local { span, ty, init: None, pat, .. }) =
+                    if let hir::StmtKind::Let(hir::Local { span, ty, init: None, pat, .. }) =
                         &ex.kind
                         && let hir::PatKind::Binding(..) = pat.kind
                         && span.contains(self.decl_span)
@@ -775,7 +779,7 @@
         }
     }
 
-    fn suggest_adding_copy_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, span: Span) {
+    fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {
         let tcx = self.infcx.tcx;
         let generics = tcx.generics_of(self.mir_def_id());
 
@@ -788,10 +792,9 @@
         };
         // Try to find predicates on *generic params* that would allow copying `ty`
         let ocx = ObligationCtxt::new(self.infcx);
-        let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
         let cause = ObligationCause::misc(span, self.mir_def_id());
 
-        ocx.register_bound(cause, self.param_env, ty, copy_did);
+        ocx.register_bound(cause, self.param_env, ty, def_id);
         let errors = ocx.select_all_or_error();
 
         // Only emit suggestion if all required predicates are on generic
@@ -877,6 +880,7 @@
                 Some(borrow_span),
                 None,
             );
+        self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
         self.buffer_error(err);
     }
 
@@ -1215,10 +1219,104 @@
         );
 
         self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
+        self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
 
         err
     }
 
+    fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) {
+        let tcx = self.infcx.tcx;
+        let hir = tcx.hir();
+        let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
+        struct FindUselessClone<'hir> {
+            pub clones: Vec<&'hir hir::Expr<'hir>>,
+        }
+        impl<'hir> FindUselessClone<'hir> {
+            pub fn new() -> Self {
+                Self { clones: vec![] }
+            }
+        }
+
+        impl<'v> Visitor<'v> for FindUselessClone<'v> {
+            fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+                // FIXME: use `lookup_method_for_diagnostic`?
+                if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind
+                    && segment.ident.name == sym::clone
+                    && args.len() == 0
+                {
+                    self.clones.push(ex);
+                }
+                hir::intravisit::walk_expr(self, ex);
+            }
+        }
+        let mut expr_finder = FindUselessClone::new();
+
+        let body = hir.body(body_id).value;
+        expr_finder.visit_expr(body);
+
+        pub struct Holds<'tcx> {
+            ty: Ty<'tcx>,
+            holds: bool,
+        }
+
+        impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
+            type Result = std::ops::ControlFlow<()>;
+
+            fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+                if t == self.ty {
+                    self.holds = true;
+                }
+                t.super_visit_with(self)
+            }
+        }
+
+        let mut types_to_constrain = FxIndexSet::default();
+
+        let local_ty = self.body.local_decls[place.local].ty;
+        let typeck_results = tcx.typeck(self.mir_def_id());
+        let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span));
+        for expr in expr_finder.clones {
+            if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind
+                && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
+                && let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
+                && rcvr_ty == ty
+                && let ty::Ref(_, inner, _) = rcvr_ty.kind()
+                && let inner = inner.peel_refs()
+                && let mut v = (Holds { ty: inner, holds: false })
+                && let _ = v.visit_ty(local_ty)
+                && v.holds
+                && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
+            {
+                err.span_label(
+                    span,
+                    format!(
+                        "this call doesn't do anything, the result is still `{rcvr_ty}` \
+                             because `{inner}` doesn't implement `Clone`",
+                    ),
+                );
+                types_to_constrain.insert(inner);
+            }
+        }
+        for ty in types_to_constrain {
+            self.suggest_adding_bounds(err, ty, clone, body.span);
+            if let ty::Adt(..) = ty.kind() {
+                // The type doesn't implement Clone.
+                let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
+                let obligation = Obligation::new(
+                    self.infcx.tcx,
+                    ObligationCause::dummy(),
+                    self.param_env,
+                    trait_ref,
+                );
+                self.infcx.err_ctxt().suggest_derive(
+                    &obligation,
+                    err,
+                    trait_ref.to_predicate(self.infcx.tcx),
+                );
+            }
+        }
+    }
+
     #[instrument(level = "debug", skip(self, err))]
     fn suggest_using_local_if_applicable(
         &self,
@@ -1995,21 +2093,14 @@
         kind: Option<WriteKind>,
     ) {
         let drop_span = place_span.1;
-        let root_place =
-            self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
+        let borrowed_local = borrow.borrowed_place.local;
 
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.var_or_use_path_span();
 
-        assert!(root_place.projection.is_empty());
-        let proper_span = self.body.local_decls[root_place.local].source_info.span;
+        let proper_span = self.body.local_decls[borrowed_local].source_info.span;
 
-        let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
-
-        if self.access_place_error_reported.contains(&(
-            Place { local: root_place.local, projection: root_place_projection },
-            borrow_span,
-        )) {
+        if self.access_place_error_reported.contains(&(Place::from(borrowed_local), borrow_span)) {
             debug!(
                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
                 borrow_span
@@ -2017,12 +2108,8 @@
             return;
         }
 
-        self.access_place_error_reported.insert((
-            Place { local: root_place.local, projection: root_place_projection },
-            borrow_span,
-        ));
+        self.access_place_error_reported.insert((Place::from(borrowed_local), borrow_span));
 
-        let borrowed_local = borrow.borrowed_place.local;
         if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
             let err =
                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
@@ -2544,9 +2631,7 @@
             };
             (format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here"))
         } else {
-            let root_place =
-                self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
-            let local = root_place.local;
+            let local = borrow.borrowed_place.local;
             match self.body.local_kind(local) {
                 LocalKind::Arg => (
                     "function parameter".to_string(),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 560928d..914f68a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1050,7 +1050,7 @@
                     );
                     err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
                 }
-                CallKind::Operator { self_arg, .. } => {
+                CallKind::Operator { self_arg, trait_id, .. } => {
                     let self_arg = self_arg.unwrap();
                     err.subdiagnostic(
                         self.dcx(),
@@ -1062,9 +1062,16 @@
                         },
                     );
                     if self.fn_self_span_reported.insert(fn_span) {
+                        let lang = self.infcx.tcx.lang_items();
                         err.subdiagnostic(
                             self.dcx(),
-                            CaptureReasonNote::LhsMoveByOperator { span: self_arg.span },
+                            if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
+                                .contains(&Some(trait_id))
+                            {
+                                CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
+                            } else {
+                                CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
+                            },
                         );
                     }
                 }
@@ -1226,20 +1233,20 @@
                             {
                                 let msg = match &errors[..] {
                                     [] => "you can `clone` the value and consume it, but this \
-                                            might not be your desired behavior"
+                                           might not be your desired behavior"
                                         .to_string(),
                                     [error] => {
                                         format!(
-                                            "you could `clone` the value and consume it, if \
-                                                the `{}` trait bound could be satisfied",
+                                            "you could `clone` the value and consume it, if the \
+                                             `{}` trait bound could be satisfied",
                                             error.obligation.predicate,
                                         )
                                     }
                                     [errors @ .., last] => {
                                         format!(
-                                            "you could `clone` the value and consume it, if \
-                                                the following trait bounds could be satisfied: {} \
-                                                and `{}`",
+                                            "you could `clone` the value and consume it, if the \
+                                             following trait bounds could be satisfied: \
+                                             {} and `{}`",
                                             errors
                                                 .iter()
                                                 .map(|e| format!("`{}`", e.obligation.predicate))
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index ebc9f1d..a27d016 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -558,7 +558,7 @@
                     hir::intravisit::walk_stmt(self, stmt);
                     let expr = match stmt.kind {
                         hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
-                        hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
+                        hir::StmtKind::Let(hir::Local { init: Some(expr), .. }) => expr,
                         _ => {
                             return;
                         }
@@ -672,11 +672,8 @@
         };
         (
             true,
-            td.as_local().and_then(|tld| match self.infcx.tcx.opt_hir_node_by_def_id(tld) {
-                Some(Node::Item(hir::Item {
-                    kind: hir::ItemKind::Trait(_, _, _, _, items),
-                    ..
-                })) => {
+            td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) {
+                Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => {
                     let mut f_in_trait_opt = None;
                     for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
                         let hi = fi.hir_id();
@@ -1305,7 +1302,7 @@
 impl<'tcx> Visitor<'tcx> for BindingFinder {
     type Result = ControlFlow<hir::HirId>;
     fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
-        if let hir::StmtKind::Local(local) = s.kind
+        if let hir::StmtKind::Let(local) = s.kind
             && local.pat.span == self.span
         {
             ControlFlow::Break(local.hir_id)
@@ -1475,11 +1472,9 @@
     if let ty::Ref(_, ty, _) = ty.kind()
         && let ty::Adt(def, _) = ty.kind()
         && let field = def.all_fields().nth(field.index())?
-        // Use the HIR types to construct the diagnostic message.
-        && let node = tcx.opt_hir_node_by_def_id(field.did.as_local()?)?
         // Now we're dealing with the actual struct that we're going to suggest a change to,
         // we can expect a field that is an immutable reference to a type.
-        && let hir::Node::Field(field) = node
+        && let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.as_local()?)
         && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
     {
         return Some(lt.ident.span.between(ty.span));
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 8bb3dc8..8a3a089 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -1,7 +1,4 @@
-//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
-//! place are formed by stripping away fields and derefs, except that
-//! we stop when we reach the deref of a shared reference. [...] "
-//!
+//! From the NLL RFC:
 //! "Shallow prefixes are found by stripping away fields, but stop at
 //! any dereference. So: writing a path like `a` is illegal if `a.b`
 //! is borrowed. But: writing `a` is legal if `*a` is borrowed,
@@ -9,9 +6,7 @@
 
 use super::MirBorrowckCtxt;
 
-use rustc_hir as hir;
-use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::mir::{PlaceRef, ProjectionElem};
 
 pub trait IsPrefixOf<'tcx> {
     fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool;
@@ -25,9 +20,7 @@
     }
 }
 
-pub(super) struct Prefixes<'cx, 'tcx> {
-    body: &'cx Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
+pub(super) struct Prefixes<'tcx> {
     kind: PrefixSet,
     next: Option<PlaceRef<'tcx>>,
 }
@@ -39,24 +32,18 @@
     All,
     /// Stops at any dereference.
     Shallow,
-    /// Stops at the deref of a shared reference.
-    Supporting,
 }
 
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Returns an iterator over the prefixes of `place`
     /// (inclusive) from longest to smallest, potentially
     /// terminating the iteration early based on `kind`.
-    pub(super) fn prefixes(
-        &self,
-        place_ref: PlaceRef<'tcx>,
-        kind: PrefixSet,
-    ) -> Prefixes<'cx, 'tcx> {
-        Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx }
+    pub(super) fn prefixes(&self, place_ref: PlaceRef<'tcx>, kind: PrefixSet) -> Prefixes<'tcx> {
+        Prefixes { next: Some(place_ref), kind }
     }
 }
 
-impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
+impl<'tcx> Iterator for Prefixes<'tcx> {
     type Item = PlaceRef<'tcx>;
     fn next(&mut self) -> Option<Self::Item> {
         let mut cursor = self.next?;
@@ -91,57 +78,23 @@
                             panic!("Subtype projection is not allowed before borrow check")
                         }
                         ProjectionElem::Deref => {
-                            // (handled below)
+                            match self.kind {
+                                PrefixSet::Shallow => {
+                                    // Shallow prefixes are found by stripping away
+                                    // fields, but stop at *any* dereference.
+                                    // So we can just stop the traversal now.
+                                    self.next = None;
+                                    return Some(cursor);
+                                }
+                                PrefixSet::All => {
+                                    // All prefixes: just blindly enqueue the base
+                                    // of the projection.
+                                    self.next = Some(cursor_base);
+                                    return Some(cursor);
+                                }
+                            }
                         }
                     }
-
-                    assert_eq!(elem, ProjectionElem::Deref);
-
-                    match self.kind {
-                        PrefixSet::Shallow => {
-                            // Shallow prefixes are found by stripping away
-                            // fields, but stop at *any* dereference.
-                            // So we can just stop the traversal now.
-                            self.next = None;
-                            return Some(cursor);
-                        }
-                        PrefixSet::All => {
-                            // All prefixes: just blindly enqueue the base
-                            // of the projection.
-                            self.next = Some(cursor_base);
-                            return Some(cursor);
-                        }
-                        PrefixSet::Supporting => {
-                            // Fall through!
-                        }
-                    }
-
-                    assert_eq!(self.kind, PrefixSet::Supporting);
-                    // Supporting prefixes: strip away fields and
-                    // derefs, except we stop at the deref of a shared
-                    // reference.
-
-                    let ty = cursor_base.ty(self.body, self.tcx).ty;
-                    match ty.kind() {
-                        ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
-                            // don't continue traversing over derefs of raw pointers or shared
-                            // borrows.
-                            self.next = None;
-                            return Some(cursor);
-                        }
-
-                        ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
-                            self.next = Some(cursor_base);
-                            return Some(cursor);
-                        }
-
-                        ty::Adt(..) if ty.is_box() => {
-                            self.next = Some(cursor_base);
-                            return Some(cursor);
-                        }
-
-                        _ => panic!("unknown type fed to Projection Deref."),
-                    }
                 }
             }
         }
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index a055ce9..77021ae 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -368,6 +368,11 @@
         #[primary_span]
         var_span: Span,
     },
+    #[note(borrowck_calling_operator_moves)]
+    UnOpMoveByOperator {
+        #[primary_span]
+        span: Span,
+    },
     #[note(borrowck_calling_operator_moves_lhs)]
     LhsMoveByOperator {
         #[primary_span]
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 18c5960..cec4792 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -71,7 +71,7 @@
     // This cannot fail because we checked all required_consts in advance.
     let val = cv
         .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
-        .expect("erroneous constant not captured by required_consts");
+        .expect("erroneous constant missed by mono item collection");
     (val, cv.ty())
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 147939d..e5f5146 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -203,57 +203,63 @@
         val: &'ll Value,
         dst: PlaceRef<'tcx, &'ll Value>,
     ) {
-        if self.is_ignore() {
-            return;
-        }
-        if self.is_sized_indirect() {
-            OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
-        } else if self.is_unsized_indirect() {
-            bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
-        } else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode {
-            // FIXME(eddyb): Figure out when the simpler Store is safe, clang
-            // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
-            let can_store_through_cast_ptr = false;
-            if can_store_through_cast_ptr {
-                bx.store(val, dst.llval, self.layout.align.abi);
-            } else {
-                // The actual return type is a struct, but the ABI
-                // adaptation code has cast it into some scalar type. The
-                // code that follows is the only reliable way I have
-                // found to do a transform like i64 -> {i32,i32}.
-                // Basically we dump the data onto the stack then memcpy it.
-                //
-                // Other approaches I tried:
-                // - Casting rust ret pointer to the foreign type and using Store
-                //   is (a) unsafe if size of foreign type > size of rust type and
-                //   (b) runs afoul of strict aliasing rules, yielding invalid
-                //   assembly under -O (specifically, the store gets removed).
-                // - Truncating foreign type to correct integral type and then
-                //   bitcasting to the struct type yields invalid cast errors.
-
-                // We instead thus allocate some scratch space...
-                let scratch_size = cast.size(bx);
-                let scratch_align = cast.align(bx);
-                let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
-                bx.lifetime_start(llscratch, scratch_size);
-
-                // ... where we first store the value...
-                bx.store(val, llscratch, scratch_align);
-
-                // ... and then memcpy it to the intended destination.
-                bx.memcpy(
-                    dst.llval,
-                    self.layout.align.abi,
-                    llscratch,
-                    scratch_align,
-                    bx.const_usize(self.layout.size.bytes()),
-                    MemFlags::empty(),
-                );
-
-                bx.lifetime_end(llscratch, scratch_size);
+        match &self.mode {
+            PassMode::Ignore => {}
+            // Sized indirect arguments
+            PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => {
+                let align = attrs.pointee_align.unwrap_or(self.layout.align.abi);
+                OperandValue::Ref(val, None, align).store(bx, dst);
             }
-        } else {
-            OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
+            // Unsized indirect qrguments
+            PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
+                bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
+            }
+            PassMode::Cast { cast, pad_i32: _ } => {
+                // FIXME(eddyb): Figure out when the simpler Store is safe, clang
+                // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
+                let can_store_through_cast_ptr = false;
+                if can_store_through_cast_ptr {
+                    bx.store(val, dst.llval, self.layout.align.abi);
+                } else {
+                    // The actual return type is a struct, but the ABI
+                    // adaptation code has cast it into some scalar type. The
+                    // code that follows is the only reliable way I have
+                    // found to do a transform like i64 -> {i32,i32}.
+                    // Basically we dump the data onto the stack then memcpy it.
+                    //
+                    // Other approaches I tried:
+                    // - Casting rust ret pointer to the foreign type and using Store
+                    //   is (a) unsafe if size of foreign type > size of rust type and
+                    //   (b) runs afoul of strict aliasing rules, yielding invalid
+                    //   assembly under -O (specifically, the store gets removed).
+                    // - Truncating foreign type to correct integral type and then
+                    //   bitcasting to the struct type yields invalid cast errors.
+
+                    // We instead thus allocate some scratch space...
+                    let scratch_size = cast.size(bx);
+                    let scratch_align = cast.align(bx);
+                    let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
+                    bx.lifetime_start(llscratch, scratch_size);
+
+                    // ... where we first store the value...
+                    bx.store(val, llscratch, scratch_align);
+
+                    // ... and then memcpy it to the intended destination.
+                    bx.memcpy(
+                        dst.llval,
+                        self.layout.align.abi,
+                        llscratch,
+                        scratch_align,
+                        bx.const_usize(self.layout.size.bytes()),
+                        MemFlags::empty(),
+                    );
+
+                    bx.lifetime_end(llscratch, scratch_size);
+                }
+            }
+            _ => {
+                OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst);
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 017843c..2af2814 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -164,6 +164,15 @@
                 end_line,
                 end_col,
             ),
+            MappingKind::Branch { true_term, false_term } => Self::branch_region(
+                Counter::from_term(true_term),
+                Counter::from_term(false_term),
+                local_file_id,
+                start_line,
+                start_col,
+                end_line,
+                end_col,
+            ),
         }
     }
 
@@ -188,9 +197,6 @@
         }
     }
 
-    // This function might be used in the future; the LLVM API is still evolving, as is coverage
-    // support.
-    #[allow(dead_code)]
     pub(crate) fn branch_region(
         counter: Counter,
         false_counter: Counter,
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 733a77d..133084b 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -88,7 +88,7 @@
         match coverage.kind {
             // Marker statements have no effect during codegen,
             // so return early and don't create `func_coverage`.
-            CoverageKind::SpanMarker => return,
+            CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => return,
             // Match exhaustively to ensure that newly-added kinds are classified correctly.
             CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } => {}
         }
@@ -108,7 +108,7 @@
 
         let Coverage { kind } = coverage;
         match *kind {
-            CoverageKind::SpanMarker => unreachable!(
+            CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
                 "unexpected marker statement {kind:?} should have caused an early return"
             ),
             CoverageKind::CounterIncrement { id } => {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index e70cc9b..f5e8d5f 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1081,6 +1081,21 @@
         }
     }
 
+    if sess.target.is_like_aix {
+        let stripcmd = "/usr/bin/strip";
+        match strip {
+            Strip::Debuginfo => {
+                // FIXME: AIX's strip utility only offers option to strip line number information.
+                strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-l"))
+            }
+            Strip::Symbols => {
+                // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
+                strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-r"))
+            }
+            Strip::None => {}
+        }
+    }
+
     Ok(())
 }
 
@@ -1201,20 +1216,29 @@
     crate_type: CrateType,
     linker: &mut dyn Linker,
 ) {
+    if sess.target.is_like_android {
+        // Sanitizer runtime libraries are provided dynamically on Android
+        // targets.
+        return;
+    }
+
+    if sess.opts.unstable_opts.external_clangrt {
+        // Linking against in-tree sanitizer runtimes is disabled via
+        // `-Z external-clangrt`
+        return;
+    }
+
+    if matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) {
+        return;
+    }
+
     // On macOS and Windows using MSVC the runtimes are distributed as dylibs
     // which should be linked to both executables and dynamic libraries.
     // Everywhere else the runtimes are currently distributed as static
     // libraries which should be linked to executables only.
-    let needs_runtime = !sess.target.is_like_android
-        && match crate_type {
-            CrateType::Executable => true,
-            CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
-                sess.target.is_like_osx || sess.target.is_like_msvc
-            }
-            CrateType::Rlib | CrateType::Staticlib => false,
-        };
-
-    if !needs_runtime {
+    if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
+        && !(sess.target.is_like_osx || sess.target.is_like_msvc)
+    {
         return;
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index b4e0544..f5640ea 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -929,6 +929,15 @@
                 // from the CodeView line tables in the object files.
                 self.cmd.arg("/DEBUG");
 
+                // Default to emitting only the file name of the PDB file into
+                // the binary instead of the full path. Emitting the full path
+                // may leak private information (such as user names).
+                // See https://github.com/rust-lang/rust/issues/87825.
+                //
+                // This default behavior can be overridden by explicitly passing
+                // `-Clink-arg=/PDBALTPATH:...` to rustc.
+                self.cmd.arg("/PDBALTPATH:%_PDB%");
+
                 // This will cause the Microsoft linker to embed .natvis info into the PDB file
                 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
                 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
@@ -1640,16 +1649,7 @@
 
     fn ehcont_guard(&mut self) {}
 
-    fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
-        match strip {
-            Strip::None => {}
-            // FIXME: -s strips the symbol table, line number information
-            // and relocation information.
-            Strip::Debuginfo | Strip::Symbols => {
-                self.cmd.arg("-s");
-            }
-        }
-    }
+    fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
 
     fn no_crt_objects(&mut self) {}
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index d532bd9..ff899c5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -21,11 +21,11 @@
     }
 
     pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> {
-        // `MirUsedCollector` visited all constants before codegen began, so if we got here there
-        // can be no more constants that fail to evaluate.
+        // `MirUsedCollector` visited all required_consts before codegen began, so if we got here
+        // there can be no more constants that fail to evaluate.
         self.monomorphize(constant.const_)
             .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
-            .expect("erroneous constant not captured by required_consts")
+            .expect("erroneous constant missed by mono item collection")
     }
 
     /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index bac10f3..387a536 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -211,7 +211,8 @@
 
     // It may seem like we should iterate over `required_consts` to ensure they all successfully
     // evaluate; however, the `MirUsedCollector` already did that during the collection phase of
-    // monomorphization so we don't have to do it again.
+    // monomorphization, and if there is an error during collection then codegen never starts -- so
+    // we don't have to do it again.
 
     fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
 
@@ -376,29 +377,45 @@
                 }
             }
 
-            if arg.is_sized_indirect() {
-                // Don't copy an indirect argument to an alloca, the caller
-                // already put it in a temporary alloca and gave it up.
-                // FIXME: lifetimes
-                let llarg = bx.get_param(llarg_idx);
-                llarg_idx += 1;
-                LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout))
-            } else if arg.is_unsized_indirect() {
-                // As the storage for the indirect argument lives during
-                // the whole function call, we just copy the fat pointer.
-                let llarg = bx.get_param(llarg_idx);
-                llarg_idx += 1;
-                let llextra = bx.get_param(llarg_idx);
-                llarg_idx += 1;
-                let indirect_operand = OperandValue::Pair(llarg, llextra);
+            match arg.mode {
+                // Sized indirect arguments
+                PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => {
+                    // Don't copy an indirect argument to an alloca, the caller already put it
+                    // in a temporary alloca and gave it up.
+                    // FIXME: lifetimes
+                    if let Some(pointee_align) = attrs.pointee_align
+                        && pointee_align < arg.layout.align.abi
+                    {
+                        // ...unless the argument is underaligned, then we need to copy it to
+                        // a higher-aligned alloca.
+                        let tmp = PlaceRef::alloca(bx, arg.layout);
+                        bx.store_fn_arg(arg, &mut llarg_idx, tmp);
+                        LocalRef::Place(tmp)
+                    } else {
+                        let llarg = bx.get_param(llarg_idx);
+                        llarg_idx += 1;
+                        LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout))
+                    }
+                }
+                // Unsized indirect qrguments
+                PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
+                    // As the storage for the indirect argument lives during
+                    // the whole function call, we just copy the fat pointer.
+                    let llarg = bx.get_param(llarg_idx);
+                    llarg_idx += 1;
+                    let llextra = bx.get_param(llarg_idx);
+                    llarg_idx += 1;
+                    let indirect_operand = OperandValue::Pair(llarg, llextra);
 
-                let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout);
-                indirect_operand.store(bx, tmp);
-                LocalRef::UnsizedPlace(tmp)
-            } else {
-                let tmp = PlaceRef::alloca(bx, arg.layout);
-                bx.store_fn_arg(arg, &mut llarg_idx, tmp);
-                LocalRef::Place(tmp)
+                    let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout);
+                    indirect_operand.store(bx, tmp);
+                    LocalRef::UnsizedPlace(tmp)
+                }
+                _ => {
+                    let tmp = PlaceRef::alloca(bx, arg.layout);
+                    bx.store_fn_arg(arg, &mut llarg_idx, tmp);
+                    LocalRef::Place(tmp)
+                }
             }
         })
         .collect::<Vec<_>>();
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index f3af633..0046190 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -374,12 +374,6 @@
 const_eval_unavailable_target_features_for_fn =
     calling a function that requires unavailable target features: {$unavailable_feats}
 
-const_eval_undefined_behavior =
-    it is undefined behavior to use this value
-
-const_eval_undefined_behavior_note =
-    The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-
 const_eval_uninhabited_enum_variant_read =
     read discriminant of an uninhabited enum variant
 const_eval_uninhabited_enum_variant_written =
@@ -434,6 +428,12 @@
 const_eval_validation_expected_ref = expected a reference
 const_eval_validation_expected_str = expected a string
 
+const_eval_validation_failure =
+    it is undefined behavior to use this value
+
+const_eval_validation_failure_note =
+    The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+
 const_eval_validation_front_matter_invalid_value = constructing invalid value
 const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path}
 
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index b6adee4..7633442 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -2,15 +2,16 @@
 
 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg};
 use rustc_hir::CRATE_HIR_ID;
+use rustc_middle::mir::interpret::Provenance;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{layout::LayoutError, ConstInt};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
-use super::{CompileTimeInterpreter, InterpCx};
+use super::CompileTimeInterpreter;
 use crate::errors::{self, FrameNote, ReportErrorExt};
-use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopType};
+use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType};
 
 /// The CTFE machine has some custom error kinds.
 #[derive(Clone, Debug)]
@@ -58,15 +59,12 @@
 
 pub fn get_span_and_frames<'tcx, 'mir>(
     tcx: TyCtxtAt<'tcx>,
-    machine: &CompileTimeInterpreter<'mir, 'tcx>,
+    stack: &[Frame<'mir, 'tcx, impl Provenance, impl Sized>],
 ) -> (Span, Vec<errors::FrameNote>)
 where
     'tcx: 'mir,
 {
-    let mut stacktrace =
-        InterpCx::<CompileTimeInterpreter<'mir, 'tcx>>::generate_stacktrace_from_stack(
-            &machine.stack,
-        );
+    let mut stacktrace = Frame::generate_stacktrace_from_stack(stack);
     // Filter out `requires_caller_location` frames.
     stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx));
     let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span);
@@ -170,7 +168,7 @@
 ) where
     L: for<'a> rustc_errors::LintDiagnostic<'a, ()>,
 {
-    let (span, frames) = get_span_and_frames(tcx, machine);
+    let (span, frames) = get_span_and_frames(tcx, &machine.stack);
 
     tcx.emit_node_span_lint(
         lint,
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 5f4408e..5a1c7cc 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -18,18 +18,18 @@
 use crate::errors::ConstEvalError;
 use crate::interpret::eval_nullary_intrinsic;
 use crate::interpret::{
-    create_static_alloc, intern_const_alloc_recursive, take_static_root_alloc, CtfeValidationMode,
-    GlobalId, Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind,
-    OpTy, RefTracking, StackPopCleanup,
+    create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate,
+    InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
+    StackPopCleanup,
 };
 
 // Returns a pointer to where the result lives
-#[instrument(level = "trace", skip(ecx, body), ret)]
-fn eval_body_using_ecx<'mir, 'tcx>(
+#[instrument(level = "trace", skip(ecx, body))]
+fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>(
     ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
     cid: GlobalId<'tcx>,
     body: &'mir mir::Body<'tcx>,
-) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
+) -> InterpResult<'tcx, R> {
     trace!(?ecx.param_env);
     let tcx = *ecx.tcx;
     assert!(
@@ -84,7 +84,10 @@
     // Intern the result
     intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
 
-    Ok(ret)
+    // Since evaluation had no errors, validate the resulting constant.
+    const_validate_mplace(&ecx, &ret, cid)?;
+
+    Ok(R::make_result(ret, ecx))
 }
 
 /// The `InterpCx` is only meant to be used to do field and index projections into constants for
@@ -282,18 +285,26 @@
 
     let instance = ty::Instance::mono(tcx, def_id.to_def_id());
     let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
-    let mut ecx = InterpCx::new(
-        tcx,
-        tcx.def_span(def_id),
-        ty::ParamEnv::reveal_all(),
-        // Statics (and promoteds inside statics) may access other statics, because unlike consts
-        // they do not have to behave "as if" they were evaluated at runtime.
-        CompileTimeInterpreter::new(CanAccessMutGlobal::Yes, CheckAlignment::Error),
-    );
-    let alloc_id = eval_in_interpreter(&mut ecx, cid, true)?.alloc_id;
-    let alloc = take_static_root_alloc(&mut ecx, alloc_id);
-    let alloc = tcx.mk_const_alloc(alloc);
-    Ok(alloc)
+    eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all())
+}
+
+pub trait InterpretationResult<'tcx> {
+    /// This function takes the place where the result of the evaluation is stored
+    /// and prepares it for returning it in the appropriate format needed by the specific
+    /// evaluation query.
+    fn make_result<'mir>(
+        mplace: MPlaceTy<'tcx>,
+        ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
+    ) -> Self;
+}
+
+impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> {
+    fn make_result<'mir>(
+        mplace: MPlaceTy<'tcx>,
+        _ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
+    ) -> Self {
+        ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty }
+    }
 }
 
 #[instrument(skip(tcx), level = "debug")]
@@ -319,92 +330,64 @@
         trace!("const eval: {:?} ({})", key, instance);
     }
 
-    let cid = key.value;
+    eval_in_interpreter(tcx, key.value, key.param_env)
+}
+
+fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
+    tcx: TyCtxt<'tcx>,
+    cid: GlobalId<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Result<R, ErrorHandled> {
     let def = cid.instance.def.def_id();
     let is_static = tcx.is_static(def);
 
     let mut ecx = InterpCx::new(
         tcx,
         tcx.def_span(def),
-        key.param_env,
+        param_env,
         // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
         // they do not have to behave "as if" they were evaluated at runtime.
         // For consts however we want to ensure they behave "as if" they were evaluated at runtime,
         // so we have to reject reading mutable global memory.
         CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
     );
-    eval_in_interpreter(&mut ecx, cid, is_static)
-}
-
-pub fn eval_in_interpreter<'mir, 'tcx>(
-    ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
-    cid: GlobalId<'tcx>,
-    is_static: bool,
-) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
-    // `is_static` just means "in static", it could still be a promoted!
-    debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some());
-
     let res = ecx.load_mir(cid.instance.def, cid.promoted);
-    match res.and_then(|body| eval_body_using_ecx(ecx, cid, body)) {
-        Err(error) => {
-            let (error, backtrace) = error.into_parts();
-            backtrace.print_backtrace();
+    res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| {
+        let (error, backtrace) = error.into_parts();
+        backtrace.print_backtrace();
 
-            let (kind, instance) = if is_static {
-                ("static", String::new())
+        let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) {
+            ("static", String::new())
+        } else {
+            // If the current item has generics, we'd like to enrich the message with the
+            // instance and its args: to show the actual compile-time values, in addition to
+            // the expression, leading to the const eval error.
+            let instance = &cid.instance;
+            if !instance.args.is_empty() {
+                let instance = with_no_trimmed_paths!(instance.to_string());
+                ("const_with_path", instance)
             } else {
-                // If the current item has generics, we'd like to enrich the message with the
-                // instance and its args: to show the actual compile-time values, in addition to
-                // the expression, leading to the const eval error.
-                let instance = &cid.instance;
-                if !instance.args.is_empty() {
-                    let instance = with_no_trimmed_paths!(instance.to_string());
-                    ("const_with_path", instance)
-                } else {
-                    ("const", String::new())
-                }
-            };
-
-            Err(super::report(
-                *ecx.tcx,
-                error,
-                None,
-                || super::get_span_and_frames(ecx.tcx, &ecx.machine),
-                |span, frames| ConstEvalError {
-                    span,
-                    error_kind: kind,
-                    instance,
-                    frame_notes: frames,
-                },
-            ))
-        }
-        Ok(mplace) => {
-            // Since evaluation had no errors, validate the resulting constant.
-
-            // Temporarily allow access to the static_root_ids for the purpose of validation.
-            let static_root_ids = ecx.machine.static_root_ids.take();
-            let res = const_validate_mplace(&ecx, &mplace, cid);
-            ecx.machine.static_root_ids = static_root_ids;
-
-            let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
-
-            // Validation failed, report an error.
-            if let Err(error) = res {
-                Err(const_report_error(&ecx, error, alloc_id))
-            } else {
-                // Convert to raw constant
-                Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
+                ("const", String::new())
             }
-        }
-    }
+        };
+
+        super::report(
+            *ecx.tcx,
+            error,
+            None,
+            || super::get_span_and_frames(ecx.tcx, ecx.stack()),
+            |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames },
+        )
+    })
 }
 
 #[inline(always)]
-pub fn const_validate_mplace<'mir, 'tcx>(
+fn const_validate_mplace<'mir, 'tcx>(
     ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
     mplace: &MPlaceTy<'tcx>,
     cid: GlobalId<'tcx>,
-) -> InterpResult<'tcx> {
+) -> Result<(), ErrorHandled> {
+    let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
     let mut ref_tracking = RefTracking::new(mplace.clone());
     let mut inner = false;
     while let Some((mplace, path)) = ref_tracking.todo.pop() {
@@ -418,7 +401,10 @@
                 CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner }
             }
         };
-        ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
+        ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)
+            // Instead of just reporting the `InterpError` via the usual machinery, we give a more targetted
+            // error about the validation failure.
+            .map_err(|error| report_validation_error(&ecx, error, alloc_id))?;
         inner = true;
     }
 
@@ -426,7 +412,7 @@
 }
 
 #[inline(always)]
-pub fn const_report_error<'mir, 'tcx>(
+fn report_validation_error<'mir, 'tcx>(
     ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
     error: InterpErrorInfo<'tcx>,
     alloc_id: AllocId,
@@ -444,7 +430,7 @@
         *ecx.tcx,
         error,
         None,
-        || crate::const_eval::get_span_and_frames(ecx.tcx, &ecx.machine),
-        move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
+        || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()),
+        move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes },
     )
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 289dcb7..d0d6adb 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -5,7 +5,7 @@
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::{self, Ty};
 
-use crate::interpret::{format_interp_error, InterpCx};
+use crate::interpret::format_interp_error;
 
 mod error;
 mod eval_queries;
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 4679026..cc32640 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -412,11 +412,11 @@
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_undefined_behavior, code = E0080)]
-pub struct UndefinedBehavior {
+#[diag(const_eval_validation_failure, code = E0080)]
+pub struct ValidationFailure {
     #[primary_span]
     pub span: Span,
-    #[note(const_eval_undefined_behavior_note)]
+    #[note(const_eval_validation_failure_note)]
     pub ub_note: Option<()>,
     #[subdiagnostic]
     pub frames: Vec<FrameNote>,
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index a484fbd..09e9cc4 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -220,9 +220,6 @@
 
     /// Overwrite the local. If the local can be overwritten in place, return a reference
     /// to do so; otherwise return the `MemPlace` to consult instead.
-    ///
-    /// Note: Before calling this, call the `before_access_local_mut` machine hook! You may be
-    /// invalidating machine invariants otherwise!
     #[inline(always)]
     pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> {
         match &mut self.value {
@@ -279,6 +276,39 @@
             }
         })
     }
+
+    /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
+    /// sanity check to detect bugs where we mix up which stack frame a place refers to.
+    #[inline(always)]
+    pub(super) fn locals_addr(&self) -> usize {
+        self.locals.raw.as_ptr().addr()
+    }
+
+    #[must_use]
+    pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec<FrameInfo<'tcx>> {
+        let mut frames = Vec::new();
+        // This deliberately does *not* honor `requires_caller_location` since it is used for much
+        // more than just panics.
+        for frame in stack.iter().rev() {
+            let span = match frame.loc {
+                Left(loc) => {
+                    // If the stacktrace passes through MIR-inlined source scopes, add them.
+                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
+                    let mut scope_data = &frame.body.source_scopes[scope];
+                    while let Some((instance, call_span)) = scope_data.inlined {
+                        frames.push(FrameInfo { span, instance });
+                        span = call_span;
+                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
+                    }
+                    span
+                }
+                Right(span) => span,
+            };
+            frames.push(FrameInfo { span, instance: frame.instance });
+        }
+        trace!("generate stacktrace: {:#?}", frames);
+        frames
+    }
 }
 
 // FIXME: only used by miri, should be removed once translatable.
@@ -645,7 +675,7 @@
     }
 
     #[inline(always)]
-    pub fn layout_of_local(
+    pub(super) fn layout_of_local(
         &self,
         frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         local: mir::Local,
@@ -896,7 +926,7 @@
         // Copy return value. Must of course happen *before* we deallocate the locals.
         let copy_ret_result = if !unwinding {
             let op = self
-                .local_to_op(self.frame(), mir::RETURN_PLACE, None)
+                .local_to_op(mir::RETURN_PLACE, None)
                 .expect("return place should always be live");
             let dest = self.frame().return_place.clone();
             let err = if self.stack().len() == 1 {
@@ -1167,36 +1197,8 @@
     }
 
     #[must_use]
-    pub fn generate_stacktrace_from_stack(
-        stack: &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>],
-    ) -> Vec<FrameInfo<'tcx>> {
-        let mut frames = Vec::new();
-        // This deliberately does *not* honor `requires_caller_location` since it is used for much
-        // more than just panics.
-        for frame in stack.iter().rev() {
-            let span = match frame.loc {
-                Left(loc) => {
-                    // If the stacktrace passes through MIR-inlined source scopes, add them.
-                    let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
-                    let mut scope_data = &frame.body.source_scopes[scope];
-                    while let Some((instance, call_span)) = scope_data.inlined {
-                        frames.push(FrameInfo { span, instance });
-                        span = call_span;
-                        scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
-                    }
-                    span
-                }
-                Right(span) => span,
-            };
-            frames.push(FrameInfo { span, instance: frame.instance });
-        }
-        trace!("generate stacktrace: {:#?}", frames);
-        frames
-    }
-
-    #[must_use]
     pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
-        Self::generate_stacktrace_from_stack(self.stack())
+        Frame::generate_stacktrace_from_stack(self.stack())
     }
 }
 
@@ -1212,18 +1214,16 @@
 {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self.place {
-            Place::Local { frame, local, offset } => {
+            Place::Local { local, offset, locals_addr } => {
+                debug_assert_eq!(locals_addr, self.ecx.frame().locals_addr());
                 let mut allocs = Vec::new();
                 write!(fmt, "{local:?}")?;
                 if let Some(offset) = offset {
                     write!(fmt, "+{:#x}", offset.bytes())?;
                 }
-                if frame != self.ecx.frame_idx() {
-                    write!(fmt, " ({} frames up)", self.ecx.frame_idx() - frame)?;
-                }
                 write!(fmt, ":")?;
 
-                match self.ecx.stack()[frame].locals[local].value {
+                match self.ecx.frame().locals[local].value {
                     LocalValue::Dead => write!(fmt, " is dead")?,
                     LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
                         write!(fmt, " is uninitialized")?
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index c30a136..17bb59a 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -176,7 +176,7 @@
     // This gives us the initial set of nested allocations, which will then all be processed
     // recursively in the loop below.
     let mut todo: Vec<_> = if is_static {
-        // Do not steal the root allocation, we need it later for `take_static_root_alloc`
+        // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`.
         // But still change its mutability to match the requested one.
         let alloc = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap();
         alloc.1.mutability = base_mutability;
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index b260112..afc4a80 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -260,24 +260,6 @@
         F2::NAN
     }
 
-    /// Called before writing the specified `local` of the `frame`.
-    /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
-    /// for ZST reads.
-    ///
-    /// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut
-    /// Frame`.
-    #[inline(always)]
-    fn before_access_local_mut<'a>(
-        _ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-        _frame: usize,
-        _local: mir::Local,
-    ) -> InterpResult<'tcx>
-    where
-        'tcx: 'mir,
-    {
-        Ok(())
-    }
-
     /// Called before a basic block terminator is executed.
     #[inline]
     fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
@@ -531,7 +513,6 @@
     #[inline(always)]
     fn after_local_allocated(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _frame: usize,
         _local: mir::Local,
         _mplace: &MPlaceTy<'tcx, Self::Provenance>,
     ) -> InterpResult<'tcx> {
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index 2ed879c..474d35b 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -39,5 +39,5 @@
 };
 
 pub(crate) use self::intrinsics::eval_nullary_intrinsic;
-pub(crate) use self::util::{create_static_alloc, take_static_root_alloc};
+pub(crate) use self::util::create_static_alloc;
 use eval_context::{from_known_layout, mir_assign_valid_types};
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 317e567..e49067a 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -13,9 +13,9 @@
 use rustc_target::abi::{self, Abi, HasDataLayout, Size};
 
 use super::{
-    alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, Frame, InterpCx,
-    InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer,
-    Projectable, Provenance, Scalar,
+    alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, InterpCx, InterpResult,
+    MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable,
+    Provenance, Scalar,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -633,17 +633,17 @@
         }
     }
 
-    /// Read from a local.
+    /// Read from a local of the current frame.
     /// Will not access memory, instead an indirect `Operand` is returned.
     ///
     /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
     /// OpTy from a local.
     pub fn local_to_op(
         &self,
-        frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         local: mir::Local,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
+        let frame = self.frame();
         let layout = self.layout_of_local(frame, local, layout)?;
         let op = *frame.locals[local].access()?;
         if matches!(op, Operand::Immediate(_)) {
@@ -661,9 +661,10 @@
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         match place.as_mplace_or_local() {
             Left(mplace) => Ok(mplace.into()),
-            Right((frame, local, offset)) => {
+            Right((local, offset, locals_addr)) => {
                 debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`.
-                let base = self.local_to_op(&self.stack()[frame], local, None)?;
+                debug_assert_eq!(locals_addr, self.frame().locals_addr());
+                let base = self.local_to_op(local, None)?;
                 Ok(match offset {
                     Some(offset) => base.offset(offset, place.layout, self)?,
                     None => {
@@ -687,7 +688,7 @@
         // here is not the entire place.
         let layout = if mir_place.projection.is_empty() { layout } else { None };
 
-        let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?;
+        let mut op = self.local_to_op(mir_place.local, layout)?;
         // Using `try_fold` turned out to be bad for performance, hence the loop.
         for elem in mir_place.projection.iter() {
             op = self.project(&op, elem)?
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 60f7710..1a2f119 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -187,11 +187,13 @@
     /// where in the local this place is located; if it is `None`, no projection has been applied.
     /// Such projections are meaningful even if the offset is 0, since they can change layouts.
     /// (Without that optimization, we'd just always be a `MemPlace`.)
-    /// Note that this only stores the frame index, not the thread this frame belongs to -- that is
-    /// implicit. This means a `Place` must never be moved across interpreter thread boundaries!
+    /// `Local` places always refer to the current stack frame, so they are unstable under
+    /// function calls/returns and switching betweens stacks of different threads!
+    /// We carry around the address of the `locals` buffer of the correct stack frame as a sanity
+    /// chec to be able to catch some cases of using a dangling `Place`.
     ///
     /// This variant shall not be used for unsized types -- those must always live in memory.
-    Local { frame: usize, local: mir::Local, offset: Option<Size> },
+    Local { local: mir::Local, offset: Option<Size>, locals_addr: usize },
 }
 
 /// An evaluated place, together with its type.
@@ -233,10 +235,10 @@
     #[inline(always)]
     pub fn as_mplace_or_local(
         &self,
-    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>)> {
+    ) -> Either<MPlaceTy<'tcx, Prov>, (mir::Local, Option<Size>, usize)> {
         match self.place {
             Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout }),
-            Place::Local { frame, local, offset } => Right((frame, local, offset)),
+            Place::Local { local, offset, locals_addr } => Right((local, offset, locals_addr)),
         }
     }
 
@@ -279,7 +281,7 @@
     ) -> InterpResult<'tcx, Self> {
         Ok(match self.as_mplace_or_local() {
             Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(),
-            Right((frame, local, old_offset)) => {
+            Right((local, old_offset, locals_addr)) => {
                 debug_assert!(layout.is_sized(), "unsized locals should live in memory");
                 assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway...
                 // `Place::Local` are always in-bounds of their surrounding local, so we can just
@@ -292,7 +294,10 @@
                         .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?,
                 );
 
-                PlaceTy { place: Place::Local { frame, local, offset: Some(new_offset) }, layout }
+                PlaceTy {
+                    place: Place::Local { local, offset: Some(new_offset), locals_addr },
+                    layout,
+                }
             }
         })
     }
@@ -331,7 +336,7 @@
 pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> {
     fn as_mplace_or_local(
         &self,
-    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, TyAndLayout<'tcx>)>;
+    ) -> Either<MPlaceTy<'tcx, Prov>, (mir::Local, Option<Size>, usize, TyAndLayout<'tcx>)>;
 
     fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>(
         &self,
@@ -343,9 +348,9 @@
     #[inline(always)]
     fn as_mplace_or_local(
         &self,
-    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, TyAndLayout<'tcx>)> {
+    ) -> Either<MPlaceTy<'tcx, Prov>, (mir::Local, Option<Size>, usize, TyAndLayout<'tcx>)> {
         self.as_mplace_or_local()
-            .map_right(|(frame, local, offset)| (frame, local, offset, self.layout))
+            .map_right(|(local, offset, locals_addr)| (local, offset, locals_addr, self.layout))
     }
 
     #[inline(always)]
@@ -361,7 +366,7 @@
     #[inline(always)]
     fn as_mplace_or_local(
         &self,
-    ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, TyAndLayout<'tcx>)> {
+    ) -> Either<MPlaceTy<'tcx, Prov>, (mir::Local, Option<Size>, usize, TyAndLayout<'tcx>)> {
         Left(self.clone())
     }
 
@@ -501,21 +506,21 @@
         Ok((mplace, len))
     }
 
+    /// Turn a local in the current frame into a place.
     pub fn local_to_place(
         &self,
-        frame: usize,
         local: mir::Local,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
         // Other parts of the system rely on `Place::Local` never being unsized.
         // So we eagerly check here if this local has an MPlace, and if yes we use it.
-        let frame_ref = &self.stack()[frame];
-        let layout = self.layout_of_local(frame_ref, local, None)?;
+        let frame = self.frame();
+        let layout = self.layout_of_local(frame, local, None)?;
         let place = if layout.is_sized() {
             // We can just always use the `Local` for sized values.
-            Place::Local { frame, local, offset: None }
+            Place::Local { local, offset: None, locals_addr: frame.locals_addr() }
         } else {
             // Unsized `Local` isn't okay (we cannot store the metadata).
-            match frame_ref.locals[local].access()? {
+            match frame.locals[local].access()? {
                 Operand::Immediate(_) => bug!(),
                 Operand::Indirect(mplace) => Place::Ptr(*mplace),
             }
@@ -530,7 +535,7 @@
         &self,
         mir_place: mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
-        let mut place = self.local_to_place(self.frame_idx(), mir_place.local)?;
+        let mut place = self.local_to_place(mir_place.local)?;
         // Using `try_fold` turned out to be bad for performance, hence the loop.
         for elem in mir_place.projection.iter() {
             place = self.project(&place, elem)?
@@ -611,15 +616,15 @@
         // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
         // but not factored as a separate function.
         let mplace = match dest.as_mplace_or_local() {
-            Right((frame, local, offset, layout)) => {
+            Right((local, offset, locals_addr, layout)) => {
                 if offset.is_some() {
                     // This has been projected to a part of this local. We could have complicated
                     // logic to still keep this local as an `Operand`... but it's much easier to
                     // just fall back to the indirect path.
                     dest.force_mplace(self)?
                 } else {
-                    M::before_access_local_mut(self, frame, local)?;
-                    match self.stack_mut()[frame].locals[local].access_mut()? {
+                    debug_assert_eq!(locals_addr, self.frame().locals_addr());
+                    match self.frame_mut().locals[local].access_mut()? {
                         Operand::Immediate(local_val) => {
                             // Local can be updated in-place.
                             *local_val = src;
@@ -627,7 +632,7 @@
                             // (*After* doing the update for borrow checker reasons.)
                             if cfg!(debug_assertions) {
                                 let local_layout =
-                                    self.layout_of_local(&self.stack()[frame], local, None)?;
+                                    self.layout_of_local(&self.frame(), local, None)?;
                                 match (src, local_layout.abi) {
                                     (Immediate::Scalar(scalar), Abi::Scalar(s)) => {
                                         assert_eq!(scalar.size(), s.size(self))
@@ -725,7 +730,7 @@
     ) -> InterpResult<'tcx> {
         let mplace = match dest.as_mplace_or_local() {
             Left(mplace) => mplace,
-            Right((frame, local, offset, layout)) => {
+            Right((local, offset, locals_addr, layout)) => {
                 if offset.is_some() {
                     // This has been projected to a part of this local. We could have complicated
                     // logic to still keep this local as an `Operand`... but it's much easier to
@@ -733,8 +738,8 @@
                     // FIXME: share the logic with `write_immediate_no_validate`.
                     dest.force_mplace(self)?
                 } else {
-                    M::before_access_local_mut(self, frame, local)?;
-                    match self.stack_mut()[frame].locals[local].access_mut()? {
+                    debug_assert_eq!(locals_addr, self.frame().locals_addr());
+                    match self.frame_mut().locals[local].access_mut()? {
                         Operand::Immediate(local) => {
                             *local = Immediate::Uninit;
                             return Ok(());
@@ -912,17 +917,16 @@
         place: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let mplace = match place.place {
-            Place::Local { frame, local, offset } => {
-                M::before_access_local_mut(self, frame, local)?;
-                let whole_local = match self.stack_mut()[frame].locals[local].access_mut()? {
+            Place::Local { local, offset, locals_addr } => {
+                debug_assert_eq!(locals_addr, self.frame().locals_addr());
+                let whole_local = match self.frame_mut().locals[local].access_mut()? {
                     &mut Operand::Immediate(local_val) => {
                         // We need to make an allocation.
 
                         // We need the layout of the local. We can NOT use the layout we got,
                         // that might e.g., be an inner field of a struct with `Scalar` layout,
                         // that has different alignment than the outer field.
-                        let local_layout =
-                            self.layout_of_local(&self.stack()[frame], local, None)?;
+                        let local_layout = self.layout_of_local(&self.frame(), local, None)?;
                         assert!(local_layout.is_sized(), "unsized locals cannot be immediate");
                         let mplace = self.allocate(local_layout, MemoryKind::Stack)?;
                         // Preserve old value. (As an optimization, we can skip this if it was uninit.)
@@ -936,11 +940,11 @@
                                 mplace.mplace,
                             )?;
                         }
-                        M::after_local_allocated(self, frame, local, &mplace)?;
+                        M::after_local_allocated(self, local, &mplace)?;
                         // Now we can call `access_mut` again, asserting it goes well, and actually
                         // overwrite things. This points to the entire allocation, not just the part
                         // the place refers to, i.e. we do this before we apply `offset`.
-                        *self.stack_mut()[frame].locals[local].access_mut().unwrap() =
+                        *self.frame_mut().locals[local].access_mut().unwrap() =
                             Operand::Indirect(mplace.mplace);
                         mplace.mplace
                     }
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 7b68a37..5ff78f7 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -357,7 +357,7 @@
             Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
             Index(local) => {
                 let layout = self.layout_of(self.tcx.types.usize)?;
-                let n = self.local_to_op(self.frame(), local, Some(layout))?;
+                let n = self.local_to_op(local, Some(layout))?;
                 let n = self.read_target_usize(&n)?;
                 self.project_index(base, n)?
             }
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index bafb8cb..82fb7ff 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -631,7 +631,7 @@
                         body.args_iter()
                             .map(|local| (
                                 local,
-                                self.layout_of_local(self.frame(), local, None).unwrap().ty
+                                self.layout_of_local(self.frame(), local, None).unwrap().ty,
                             ))
                             .collect::<Vec<_>>()
                     );
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 086475f..c83ef14 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,14 +1,15 @@
-use crate::const_eval::CompileTimeEvalContext;
+use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult};
 use crate::interpret::{MemPlaceMeta, MemoryKind};
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::mir::interpret::{AllocId, Allocation, InterpResult, Pointer};
+use rustc_middle::mir;
+use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use std::ops::ControlFlow;
 
-use super::MPlaceTy;
+use super::{InterpCx, MPlaceTy};
 
 /// Checks whether a type contains generic parameters which must be instantiated.
 ///
@@ -80,11 +81,15 @@
     }
 }
 
-pub(crate) fn take_static_root_alloc<'mir, 'tcx: 'mir>(
-    ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
-    alloc_id: AllocId,
-) -> Allocation {
-    ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1
+impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> {
+    fn make_result<'mir>(
+        mplace: MPlaceTy<'tcx>,
+        ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
+    ) -> Self {
+        let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
+        let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1;
+        ecx.tcx.mk_const_alloc(alloc)
+    }
 }
 
 pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>(
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 5183606..1e7ee20 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -14,6 +14,7 @@
 #![feature(generic_nonzero)]
 #![feature(let_chains)]
 #![feature(slice_ptr_get)]
+#![feature(strict_provenance)]
 #![feature(never_type)]
 #![feature(trait_alias)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs
index 30403a6..c7f66b2 100644
--- a/compiler/rustc_data_structures/src/memmap.rs
+++ b/compiler/rustc_data_structures/src/memmap.rs
@@ -18,8 +18,14 @@
     /// However in practice most callers do not ensure this, so uses of this function are likely unsound.
     #[inline]
     pub unsafe fn map(file: File) -> io::Result<Self> {
-        // Safety: the caller must ensure that this is safe.
-        unsafe { memmap2::Mmap::map(&file).map(Mmap) }
+        // By default, memmap2 creates shared mappings, implying that we could see updates to the
+        // file through the mapping. That would violate our precondition; so by requesting a
+        // map_copy_read_only we do not lose anything.
+        // This mapping mode also improves our support for filesystems such as cacheless virtiofs.
+        // For more details see https://github.com/rust-lang/rust/issues/122262
+        //
+        // SAFETY: The caller must ensure that this is safe.
+        unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file).map(Mmap) }
     }
 }
 
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index c448835..938f9f0 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -28,7 +28,7 @@
     markdown, ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult,
 };
 use rustc_feature::find_gated_cfg;
-use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
+use rustc_interface::util::{self, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
@@ -37,6 +37,7 @@
 use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType};
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
+use rustc_session::output::collect_crate_types;
 use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::FileLoader;
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 0c3e7fb..5d345e7 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -189,7 +189,8 @@
     );
 }
 
-pub trait SubdiagMessageOp<G> = Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
+pub trait SubdiagMessageOp<G: EmissionGuarantee> =
+    Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
 
 /// Trait implemented by lint types. This should not be implemented manually. Instead, use
 /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 57b8df5..4f033e3 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2086,7 +2086,7 @@
                 }
                 if !self.short_message {
                     for child in children {
-                        assert!(child.level.can_be_top_or_sub().1);
+                        assert!(child.level.can_be_subdiag());
                         let span = &child.span;
                         if let Err(err) = self.emit_messages_default_inner(
                             span,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 286d462..723f13d 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -526,12 +526,15 @@
     UndeterminedMacroResolution,
 }
 
-fn default_track_diagnostic(diag: DiagInner, f: &mut dyn FnMut(DiagInner)) {
+fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
     (*f)(diag)
 }
 
-pub static TRACK_DIAGNOSTIC: AtomicRef<fn(DiagInner, &mut dyn FnMut(DiagInner))> =
-    AtomicRef::new(&(default_track_diagnostic as _));
+/// Diagnostics emitted by `DiagCtxtInner::emit_diagnostic` are passed through this function. Used
+/// for tracking by incremental, to replay diagnostics as necessary.
+pub static TRACK_DIAGNOSTIC: AtomicRef<
+    fn(DiagInner, &mut dyn FnMut(DiagInner) -> Option<ErrorGuaranteed>) -> Option<ErrorGuaranteed>,
+> = AtomicRef::new(&(default_track_diagnostic as _));
 
 #[derive(Copy, Clone, Default)]
 pub struct DiagCtxtFlags {
@@ -1422,74 +1425,103 @@
 
     // Return value is only `Some` if the level is `Error` or `DelayedBug`.
     fn emit_diagnostic(&mut self, mut diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
-        assert!(diagnostic.level.can_be_top_or_sub().0);
-
-        if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
-            // The `LintExpectationId` can be stable or unstable depending on when it was created.
-            // Diagnostics created before the definition of `HirId`s are unstable and can not yet
-            // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
-            // a stable one by the `LintLevelsBuilder`.
-            if let LintExpectationId::Unstable { .. } = expectation_id {
-                self.unstable_expect_diagnostics.push(diagnostic);
-                return None;
-            }
-            self.suppressed_expected_diag = true;
-            self.fulfilled_expectations.insert(expectation_id.normalize());
-        }
-
         if diagnostic.has_future_breakage() {
             // Future breakages aren't emitted if they're `Level::Allow`,
             // but they still need to be constructed and stashed below,
             // so they'll trigger the must_produce_diag check.
-            self.suppressed_expected_diag = true;
+            assert!(matches!(diagnostic.level, Error | Warning | Allow));
             self.future_breakage_diagnostics.push(diagnostic.clone());
         }
 
-        // Note that because this comes before the `match` below,
-        // `-Zeagerly-emit-delayed-bugs` continues to work even after we've
-        // issued an error and stopped recording new delayed bugs.
-        if diagnostic.level == DelayedBug && self.flags.eagerly_emit_delayed_bugs {
-            diagnostic.level = Error;
-        }
-
+        // We call TRACK_DIAGNOSTIC with an empty closure for the cases that
+        // return early *and* have some kind of side-effect, except where
+        // noted.
         match diagnostic.level {
-            // This must come after the possible promotion of `DelayedBug` to
-            // `Error` above.
-            Fatal | Error if self.treat_next_err_as_bug() => {
-                diagnostic.level = Bug;
+            Bug => {}
+            Fatal | Error => {
+                if self.treat_next_err_as_bug() {
+                    // `Fatal` and `Error` can be promoted to `Bug`.
+                    diagnostic.level = Bug;
+                }
             }
             DelayedBug => {
-                // If we have already emitted at least one error, we don't need
-                // to record the delayed bug, because it'll never be used.
-                return if let Some(guar) = self.has_errors() {
-                    Some(guar)
+                // Note that because we check these conditions first,
+                // `-Zeagerly-emit-delayed-bugs` and `-Ztreat-err-as-bug`
+                // continue to work even after we've issued an error and
+                // stopped recording new delayed bugs.
+                if self.flags.eagerly_emit_delayed_bugs {
+                    // `DelayedBug` can be promoted to `Error` or `Bug`.
+                    if self.treat_next_err_as_bug() {
+                        diagnostic.level = Bug;
+                    } else {
+                        diagnostic.level = Error;
+                    }
                 } else {
-                    let backtrace = std::backtrace::Backtrace::capture();
-                    // This `unchecked_error_guaranteed` is valid. It is where the
-                    // `ErrorGuaranteed` for delayed bugs originates. See
-                    // `DiagCtxtInner::drop`.
-                    #[allow(deprecated)]
-                    let guar = ErrorGuaranteed::unchecked_error_guaranteed();
-                    self.delayed_bugs
-                        .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
-                    Some(guar)
-                };
+                    // If we have already emitted at least one error, we don't need
+                    // to record the delayed bug, because it'll never be used.
+                    return if let Some(guar) = self.has_errors() {
+                        Some(guar)
+                    } else {
+                        // No `TRACK_DIAGNOSTIC` call is needed, because the
+                        // incremental session is deleted if there is a delayed
+                        // bug. This also saves us from cloning the diagnostic.
+                        let backtrace = std::backtrace::Backtrace::capture();
+                        // This `unchecked_error_guaranteed` is valid. It is where the
+                        // `ErrorGuaranteed` for delayed bugs originates. See
+                        // `DiagCtxtInner::drop`.
+                        #[allow(deprecated)]
+                        let guar = ErrorGuaranteed::unchecked_error_guaranteed();
+                        self.delayed_bugs
+                            .push((DelayedDiagInner::with_backtrace(diagnostic, backtrace), guar));
+                        Some(guar)
+                    };
+                }
             }
-            Warning if !self.flags.can_emit_warnings => {
+            ForceWarning(None) => {} // `ForceWarning(Some(...))` is below, with `Expect`
+            Warning => {
+                if !self.flags.can_emit_warnings {
+                    // We are not emitting warnings.
+                    if diagnostic.has_future_breakage() {
+                        // The side-effect is at the top of this method.
+                        TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
+                    }
+                    return None;
+                }
+            }
+            Note | Help | FailureNote => {}
+            OnceNote | OnceHelp => panic!("bad level: {:?}", diagnostic.level),
+            Allow => {
+                // Nothing emitted for allowed lints.
                 if diagnostic.has_future_breakage() {
-                    (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
+                    // The side-effect is at the top of this method.
+                    TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
+                    self.suppressed_expected_diag = true;
                 }
                 return None;
             }
-            Allow | Expect(_) => {
-                (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
-                return None;
+            Expect(expect_id) | ForceWarning(Some(expect_id)) => {
+                // Diagnostics created before the definition of `HirId`s are
+                // unstable and can not yet be stored. Instead, they are
+                // buffered until the `LintExpectationId` is replaced by a
+                // stable one by the `LintLevelsBuilder`.
+                if let LintExpectationId::Unstable { .. } = expect_id {
+                    // We don't call TRACK_DIAGNOSTIC because we wait for the
+                    // unstable ID to be updated, whereupon the diagnostic will
+                    // be passed into this method again.
+                    self.unstable_expect_diagnostics.push(diagnostic);
+                    return None;
+                }
+                self.fulfilled_expectations.insert(expect_id.normalize());
+                if let Expect(_) = diagnostic.level {
+                    // Nothing emitted here for expected lints.
+                    TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
+                    self.suppressed_expected_diag = true;
+                    return None;
+                }
             }
-            _ => {}
         }
 
-        let mut guaranteed = None;
-        (*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| {
+        TRACK_DIAGNOSTIC(diagnostic, &mut |mut diagnostic| {
             if let Some(code) = diagnostic.code {
                 self.emitted_diagnostic_codes.insert(code);
             }
@@ -1552,17 +1584,17 @@
                 // `ErrorGuaranteed` for errors and lint errors originates.
                 #[allow(deprecated)]
                 let guar = ErrorGuaranteed::unchecked_error_guaranteed();
-                guaranteed = Some(guar);
                 if is_lint {
                     self.lint_err_guars.push(guar);
                 } else {
                     self.err_guars.push(guar);
                 }
                 self.panic_if_treat_err_as_bug();
+                Some(guar)
+            } else {
+                None
             }
-        });
-
-        guaranteed
+        })
     }
 
     fn treat_err_as_bug(&self) -> bool {
@@ -1863,23 +1895,13 @@
         matches!(*self, FailureNote)
     }
 
-    pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
-        match self {
-            Expect(id) | ForceWarning(Some(id)) => Some(*id),
-            _ => None,
-        }
-    }
-
-    // Can this level be used in a top-level diagnostic message and/or a
-    // subdiagnostic message?
-    fn can_be_top_or_sub(&self) -> (bool, bool) {
+    // Can this level be used in a subdiagnostic message?
+    fn can_be_subdiag(&self) -> bool {
         match self {
             Bug | DelayedBug | Fatal | Error | ForceWarning(_) | FailureNote | Allow
-            | Expect(_) => (true, false),
+            | Expect(_) => false,
 
-            Warning | Note | Help => (true, true),
-
-            OnceNote | OnceHelp => (false, true),
+            Warning | Note | Help | OnceNote | OnceHelp => true,
         }
     }
 }
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 989b7b4..e71047f 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -218,7 +218,7 @@
     }
 
     pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt {
-        ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
+        ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Let(local), span }
     }
 
     pub fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3544a8f..cac1e8f 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1389,7 +1389,7 @@
             StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),
             StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),
             StmtKind::Expr(..) => unreachable!(),
-            StmtKind::Local(..) | StmtKind::Empty => false,
+            StmtKind::Let(..) | StmtKind::Empty => false,
         }
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 38848b2..e5a29f3 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -580,6 +580,13 @@
         "`may_dangle` has unstable semantics and may be removed in the future",
     ),
 
+    rustc_attr!(
+        rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing,
+        @only_local: true,
+        "`rustc_never_type_fallback` is used to experiment with never type fallback and work on \
+         never type stabilization, and will never be stable"
+    ),
+
     // ==========================================================================
     // Internal attributes: Runtime related:
     // ==========================================================================
@@ -894,56 +901,93 @@
     ),
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing, @only_local: true),
+    rustc_attr!(
+        TEST, rustc_variance_of_opaques, Normal, template!(Word),
+        WarnFollowing, @only_local: true
+    ),
+    rustc_attr!(
+        TEST, rustc_hidden_type_of_opaques, Normal, template!(Word),
+        WarnFollowing, @only_local: true),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
-    rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
-    rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(
+        TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."),
+        WarnFollowing, @only_local: true
+    ),
+    rustc_attr!(
+        TEST, rustc_regions, Normal, template!(Word),
+        WarnFollowing, @only_local: true
+    ),
     rustc_attr!(
         TEST, rustc_error, Normal,
         template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
     ),
-    rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(
+        TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing,
+        @only_local: true
+    ),
     rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
     rustc_attr!(
-        TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk
+        TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"),
+        DuplicatesOk, @only_local: true
     ),
     rustc_attr!(
-        TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk
+        TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"),
+        DuplicatesOk, @only_local: true
     ),
     rustc_attr!(
         TEST, rustc_clean, Normal,
         template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
-        DuplicatesOk,
+        DuplicatesOk, @only_local: true
     ),
     rustc_attr!(
         TEST, rustc_partition_reused, Normal,
-        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk,
+        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, @only_local: true
     ),
     rustc_attr!(
         TEST, rustc_partition_codegened, Normal,
-        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk,
+        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, @only_local: true
     ),
     rustc_attr!(
         TEST, rustc_expected_cgu_reuse, Normal,
         template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
+        @only_local: true
     ),
-    rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(
+        TEST, rustc_symbol_name, Normal, template!(Word), WarnFollowing,
+        @only_local: true
+    ),
     rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_def_path, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(
+        TEST, rustc_def_path, Normal, template!(Word), WarnFollowing,
+        @only_local: true
+    ),
     rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."), DuplicatesOk),
     gated!(
         custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#),
-        ErrorFollowing, "the `#[custom_mir]` attribute is just used for the Rust test suite",
+        ErrorFollowing, @only_local: true,
+        "the `#[custom_mir]` attribute is just used for the Rust test suite",
     ),
-    rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(
+        TEST, rustc_dump_program_clauses, Normal, template!(Word), WarnFollowing,
+        @only_local: true
+    ),
+    rustc_attr!(
+        TEST, rustc_dump_env_program_clauses, Normal, template!(Word), WarnFollowing,
+        @only_local: true
+    ),
+    rustc_attr!(
+        TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing,
+        @only_local: true
+    ),
     rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word), WarnFollowing),
-    rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk),
+    rustc_attr!(
+        TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), DuplicatesOk,
+        @only_local: true
+    ),
     gated!(
         omit_gdb_pretty_printer_section, Normal, template!(Word), WarnFollowing,
+        @only_local: true,
         "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
     ),
     rustc_attr!(
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 52421fc..c3f2169 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -463,6 +463,10 @@
     (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
     /// Allows defining `extern type`s.
     (unstable, extern_types, "1.23.0", Some(43467)),
+    /// Allow using 128-bit (quad precision) floating point numbers.
+    (unstable, f128, "CURRENT_RUSTC_VERSION", Some(116909)),
+    /// Allow using 16-bit (half precision) floating point numbers.
+    (unstable, f16, "CURRENT_RUSTC_VERSION", Some(116909)),
     /// Allows the use of `#[ffi_const]` on foreign functions.
     (unstable, ffi_const, "1.45.0", Some(58328)),
     /// Allows the use of `#[ffi_pure]` on foreign functions.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 8a7d3299..e21d312 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1209,7 +1209,7 @@
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub enum StmtKind<'hir> {
     /// A local (`let`) binding.
-    Local(&'hir Local<'hir>),
+    Let(&'hir Local<'hir>),
 
     /// An item binding.
     Item(ItemId),
@@ -1253,11 +1253,11 @@
     pub body: &'hir Expr<'hir>,
 }
 
-/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a Local), occurring in an `if-let` or
-/// `let-else`, evaluating to a boolean. Typically the pattern is refutable.
+/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a [`Local`]), occurring in an `if-let`
+/// or `let-else`, evaluating to a boolean. Typically the pattern is refutable.
 ///
-/// In an if-let, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of the
-/// desugaring to if-let. Only let-else supports the type annotation at present.
+/// In an `if let`, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of
+/// the desugaring to if-let. Only let-else supports the type annotation at present.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct Let<'hir> {
     pub span: Span,
@@ -2444,7 +2444,7 @@
 
 impl PrimTy {
     /// All of the primitive types
-    pub const ALL: [Self; 17] = [
+    pub const ALL: [Self; 19] = [
         // any changes here should also be reflected in `PrimTy::from_name`
         Self::Int(IntTy::I8),
         Self::Int(IntTy::I16),
@@ -2458,9 +2458,10 @@
         Self::Uint(UintTy::U64),
         Self::Uint(UintTy::U128),
         Self::Uint(UintTy::Usize),
+        Self::Float(FloatTy::F16),
         Self::Float(FloatTy::F32),
         Self::Float(FloatTy::F64),
-        // FIXME(f16_f128): add these when enabled below
+        Self::Float(FloatTy::F128),
         Self::Bool,
         Self::Char,
         Self::Str,
@@ -2508,12 +2509,10 @@
             sym::u64 => Self::Uint(UintTy::U64),
             sym::u128 => Self::Uint(UintTy::U128),
             sym::usize => Self::Uint(UintTy::Usize),
+            sym::f16 => Self::Float(FloatTy::F16),
             sym::f32 => Self::Float(FloatTy::F32),
             sym::f64 => Self::Float(FloatTy::F64),
-            // FIXME(f16_f128): enabling these will open the gates of f16 and f128 being
-            // understood by rustc.
-            // sym::f16 => Self::Float(FloatTy::F16),
-            // sym::f128 => Self::Float(FloatTy::F128),
+            sym::f128 => Self::Float(FloatTy::F128),
             sym::bool => Self::Bool,
             sym::char => Self::Char,
             sym::str => Self::Str,
@@ -2553,6 +2552,11 @@
     pub in_trait: bool,
 }
 
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
+pub struct AssocOpaqueTy {
+    // Add some data if necessary
+}
+
 /// From whence the opaque type came.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
 pub enum OpaqueTyOrigin {
@@ -3363,6 +3367,7 @@
     TraitItem(&'hir TraitItem<'hir>),
     ImplItem(&'hir ImplItem<'hir>),
     Crate(&'hir Mod<'hir>),
+    AssocOpaqueTy(&'hir AssocOpaqueTy),
 }
 
 impl<'hir> OwnerNode<'hir> {
@@ -3372,7 +3377,7 @@
             | OwnerNode::ForeignItem(ForeignItem { ident, .. })
             | OwnerNode::ImplItem(ImplItem { ident, .. })
             | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident),
-            OwnerNode::Crate(..) => None,
+            OwnerNode::Crate(..) | OwnerNode::AssocOpaqueTy(..) => None,
         }
     }
 
@@ -3385,6 +3390,7 @@
             | OwnerNode::ImplItem(ImplItem { span, .. })
             | OwnerNode::TraitItem(TraitItem { span, .. }) => span,
             OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => inner_span,
+            OwnerNode::AssocOpaqueTy(..) => unreachable!(),
         }
     }
 
@@ -3443,6 +3449,7 @@
             | OwnerNode::ImplItem(ImplItem { owner_id, .. })
             | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id,
             OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
+            OwnerNode::AssocOpaqueTy(..) => unreachable!(),
         }
     }
 
@@ -3486,6 +3493,7 @@
             OwnerNode::ImplItem(n) => Node::ImplItem(n),
             OwnerNode::TraitItem(n) => Node::TraitItem(n),
             OwnerNode::Crate(n) => Node::Crate(n),
+            OwnerNode::AssocOpaqueTy(n) => Node::AssocOpaqueTy(n),
         }
     }
 }
@@ -3523,6 +3531,7 @@
     WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>),
     // FIXME: Merge into `Node::Infer`.
     ArrayLenInfer(&'hir InferArg),
+    AssocOpaqueTy(&'hir AssocOpaqueTy),
     // Span by reference to minimize `Node`'s size
     #[allow(rustc::pass_by_value)]
     Err(&'hir Span),
@@ -3573,6 +3582,7 @@
             | Node::Infer(..)
             | Node::WhereBoundPredicate(..)
             | Node::ArrayLenInfer(..)
+            | Node::AssocOpaqueTy(..)
             | Node::Err(..) => None,
         }
     }
@@ -3678,6 +3688,7 @@
             Node::TraitItem(i) => Some(OwnerNode::TraitItem(i)),
             Node::ImplItem(i) => Some(OwnerNode::ImplItem(i)),
             Node::Crate(i) => Some(OwnerNode::Crate(i)),
+            Node::AssocOpaqueTy(i) => Some(OwnerNode::AssocOpaqueTy(i)),
             _ => None,
         }
     }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 32b4bf3..fbbad38 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -627,7 +627,7 @@
 pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result {
     try_visit!(visitor.visit_id(statement.hir_id));
     match statement.kind {
-        StmtKind::Local(ref local) => visitor.visit_local(local),
+        StmtKind::Let(ref local) => visitor.visit_local(local),
         StmtKind::Item(item) => visitor.visit_nested_item(item),
         StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
             visitor.visit_expr(expression)
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 6caba6f..37fbf45 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -22,7 +22,7 @@
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
 
-impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
+impl<'tcx> dyn AstConv<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
     pub(crate) fn complain_about_missing_type_params(
@@ -349,6 +349,118 @@
         })
     }
 
+    pub(super) fn report_ambiguous_associated_type(
+        &self,
+        span: Span,
+        types: &[String],
+        traits: &[String],
+        name: Symbol,
+    ) -> ErrorGuaranteed {
+        let mut err =
+            struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
+        if self
+            .tcx()
+            .resolutions(())
+            .confused_type_with_std_module
+            .keys()
+            .any(|full_span| full_span.contains(span))
+        {
+            err.span_suggestion_verbose(
+                span.shrink_to_lo(),
+                "you are looking for the module in `std`, not the primitive type",
+                "std::",
+                Applicability::MachineApplicable,
+            );
+        } else {
+            let mut types = types.to_vec();
+            types.sort();
+            let mut traits = traits.to_vec();
+            traits.sort();
+            match (&types[..], &traits[..]) {
+                ([], []) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        format!(
+                            "if there were a type named `Type` that implements a trait named \
+                             `Trait` with associated type `{name}`, you could use the \
+                             fully-qualified path",
+                        ),
+                        format!("<Type as Trait>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([], [trait_str]) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        format!(
+                            "if there were a type named `Example` that implemented `{trait_str}`, \
+                             you could use the fully-qualified path",
+                        ),
+                        format!("<Example as {trait_str}>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([], traits) => {
+                    err.span_suggestions(
+                        span,
+                        format!(
+                            "if there were a type named `Example` that implemented one of the \
+                             traits with associated type `{name}`, you could use the \
+                             fully-qualified path",
+                        ),
+                        traits
+                            .iter()
+                            .map(|trait_str| format!("<Example as {trait_str}>::{name}"))
+                            .collect::<Vec<_>>(),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([type_str], []) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        format!(
+                            "if there were a trait named `Example` with associated type `{name}` \
+                             implemented for `{type_str}`, you could use the fully-qualified path",
+                        ),
+                        format!("<{type_str} as Example>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                (types, []) => {
+                    err.span_suggestions(
+                        span,
+                        format!(
+                            "if there were a trait named `Example` with associated type `{name}` \
+                             implemented for one of the types, you could use the fully-qualified \
+                             path",
+                        ),
+                        types
+                            .into_iter()
+                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                (types, traits) => {
+                    let mut suggestions = vec![];
+                    for type_str in types {
+                        for trait_str in traits {
+                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+                        }
+                    }
+                    err.span_suggestions(
+                        span,
+                        "use fully-qualified syntax",
+                        suggestions,
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
     pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
         &self,
         name: Ident,
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 63afa4f..428eea2 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -409,15 +409,12 @@
     seg: &hir::PathSegment<'_>,
     is_method_call: IsMethodCall,
 ) -> GenericArgCountResult {
-    let empty_args = hir::GenericArgs::none();
-    let gen_args = seg.args.unwrap_or(&empty_args);
     let gen_pos = match is_method_call {
         IsMethodCall::Yes => GenericArgPosition::MethodCall,
         IsMethodCall::No => GenericArgPosition::Value,
     };
     let has_self = generics.parent.is_none() && generics.has_self;
-
-    check_generic_arg_count(tcx, def_id, seg, generics, gen_args, gen_pos, has_self, seg.infer_args)
+    check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self)
 }
 
 /// Checks that the correct number of generic arguments have been provided.
@@ -428,11 +425,10 @@
     def_id: DefId,
     seg: &hir::PathSegment<'_>,
     gen_params: &ty::Generics,
-    gen_args: &hir::GenericArgs<'_>,
     gen_pos: GenericArgPosition,
     has_self: bool,
-    infer_args: bool,
 ) -> GenericArgCountResult {
+    let gen_args = seg.args();
     let default_counts = gen_params.own_defaults();
     let param_counts = gen_params.own_counts();
 
@@ -453,7 +449,7 @@
         .count();
     let named_const_param_count = param_counts.consts - synth_const_param_count;
     let infer_lifetimes =
-        (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
+        (gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params();
 
     if gen_pos != GenericArgPosition::Type
         && let Some(b) = gen_args.bindings.first()
@@ -586,7 +582,7 @@
     };
 
     let args_correct = {
-        let expected_min = if infer_args {
+        let expected_min = if seg.infer_args {
             0
         } else {
             param_counts.consts + named_type_param_count
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index fb5f342..b421a33 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -8,7 +8,7 @@
 
 use super::AstConv;
 
-impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
+impl<'tcx> dyn AstConv<'tcx> + '_ {
     /// Make sure that we are in the condition to suggest the blanket implementation.
     pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>(
         &self,
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 25df763..401dd76 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -214,7 +214,7 @@
     ) -> ty::GenericArg<'tcx>;
 }
 
-impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
+impl<'tcx> dyn AstConv<'tcx> + '_ {
     #[instrument(level = "debug", skip(self), ret)]
     pub fn ast_region_to_region(
         &self,
@@ -284,8 +284,6 @@
             def_id,
             &[],
             item_segment,
-            item_segment.args(),
-            item_segment.infer_args,
             None,
             ty::BoundConstness::NotConst,
         );
@@ -330,14 +328,12 @@
     /// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two
     /// lists: `[Vec<u8>, u8, 'a]`.
     #[instrument(level = "debug", skip(self, span), ret)]
-    fn create_args_for_ast_path<'a>(
+    fn create_args_for_ast_path(
         &self,
         span: Span,
         def_id: DefId,
         parent_args: &[ty::GenericArg<'tcx>],
-        seg: &hir::PathSegment<'_>,
-        generic_args: &'a hir::GenericArgs<'tcx>,
-        infer_args: bool,
+        segment: &hir::PathSegment<'tcx>,
         self_ty: Option<Ty<'tcx>>,
         constness: ty::BoundConstness,
     ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
@@ -365,12 +361,10 @@
         let mut arg_count = check_generic_arg_count(
             tcx,
             def_id,
-            seg,
+            segment,
             generics,
-            generic_args,
             GenericArgPosition::Type,
             self_ty.is_some(),
-            infer_args,
         );
 
         if let Err(err) = &arg_count.correct
@@ -388,7 +382,7 @@
         }
 
         struct InstantiationsForAstPathCtxt<'a, 'tcx> {
-            astconv: &'a (dyn AstConv<'tcx> + 'a),
+            astconv: &'a dyn AstConv<'tcx>,
             def_id: DefId,
             generic_args: &'a GenericArgs<'tcx>,
             span: Span,
@@ -547,9 +541,9 @@
             astconv: self,
             def_id,
             span,
-            generic_args,
+            generic_args: segment.args(),
             inferred_params: vec![],
-            infer_args,
+            infer_args: segment.infer_args,
         };
         if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
             && generics.has_self
@@ -592,8 +586,6 @@
             item_def_id,
             parent_args,
             item_segment,
-            item_segment.args(),
-            item_segment.infer_args,
             None,
             ty::BoundConstness::NotConst,
         );
@@ -661,7 +653,6 @@
     ) -> GenericArgCountResult {
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
         let trait_segment = trait_ref.path.segments.last().unwrap();
-        let args = trait_segment.args();
 
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
@@ -671,8 +662,6 @@
             trait_def_id,
             &[],
             trait_segment,
-            args,
-            trait_segment.infer_args,
             Some(self_ty),
             constness,
         );
@@ -690,7 +679,7 @@
         bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
 
         let mut dup_bindings = FxIndexMap::default();
-        for binding in args.bindings {
+        for binding in trait_segment.args().bindings {
             // Don't register additional associated type bounds for negative bounds,
             // since we should have emitten an error for them earlier, and they will
             // not be well-formed!
@@ -729,12 +718,14 @@
         // FIXME(effects) move all host param things in astconv to hir lowering
         constness: ty::BoundConstness,
     ) -> ty::TraitRef<'tcx> {
-        let (generic_args, _) = self.create_args_for_ast_trait_ref(
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
+
+        let (generic_args, _) = self.create_args_for_ast_path(
             span,
             trait_def_id,
-            self_ty,
+            &[],
             trait_segment,
-            is_impl,
+            Some(self_ty),
             constness,
         );
         if let Some(b) = trait_segment.args().bindings.first() {
@@ -743,30 +734,6 @@
         ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
     }
 
-    #[instrument(level = "debug", skip(self, span))]
-    fn create_args_for_ast_trait_ref<'a>(
-        &self,
-        span: Span,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        trait_segment: &'a hir::PathSegment<'tcx>,
-        is_impl: bool,
-        constness: ty::BoundConstness,
-    ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
-
-        self.create_args_for_ast_path(
-            span,
-            trait_def_id,
-            &[],
-            trait_segment,
-            trait_segment.args(),
-            trait_segment.infer_args,
-            Some(self_ty),
-            constness,
-        )
-    }
-
     fn trait_defines_associated_item_named(
         &self,
         trait_def_id: DefId,
@@ -801,115 +768,6 @@
         }
     }
 
-    fn report_ambiguous_associated_type(
-        &self,
-        span: Span,
-        types: &[String],
-        traits: &[String],
-        name: Symbol,
-    ) -> ErrorGuaranteed {
-        let mut err =
-            struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
-        if self
-            .tcx()
-            .resolutions(())
-            .confused_type_with_std_module
-            .keys()
-            .any(|full_span| full_span.contains(span))
-        {
-            err.span_suggestion_verbose(
-                span.shrink_to_lo(),
-                "you are looking for the module in `std`, not the primitive type",
-                "std::",
-                Applicability::MachineApplicable,
-            );
-        } else {
-            let mut types = types.to_vec();
-            types.sort();
-            let mut traits = traits.to_vec();
-            traits.sort();
-            match (&types[..], &traits[..]) {
-                ([], []) => {
-                    err.span_suggestion_verbose(
-                        span,
-                        format!(
-                            "if there were a type named `Type` that implements a trait named \
-                             `Trait` with associated type `{name}`, you could use the \
-                             fully-qualified path",
-                        ),
-                        format!("<Type as Trait>::{name}"),
-                        Applicability::HasPlaceholders,
-                    );
-                }
-                ([], [trait_str]) => {
-                    err.span_suggestion_verbose(
-                        span,
-                        format!(
-                            "if there were a type named `Example` that implemented `{trait_str}`, \
-                             you could use the fully-qualified path",
-                        ),
-                        format!("<Example as {trait_str}>::{name}"),
-                        Applicability::HasPlaceholders,
-                    );
-                }
-                ([], traits) => {
-                    err.span_suggestions(
-                        span,
-                        format!(
-                            "if there were a type named `Example` that implemented one of the \
-                             traits with associated type `{name}`, you could use the \
-                             fully-qualified path",
-                        ),
-                        traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
-                        Applicability::HasPlaceholders,
-                    );
-                }
-                ([type_str], []) => {
-                    err.span_suggestion_verbose(
-                        span,
-                        format!(
-                            "if there were a trait named `Example` with associated type `{name}` \
-                             implemented for `{type_str}`, you could use the fully-qualified path",
-                        ),
-                        format!("<{type_str} as Example>::{name}"),
-                        Applicability::HasPlaceholders,
-                    );
-                }
-                (types, []) => {
-                    err.span_suggestions(
-                        span,
-                        format!(
-                            "if there were a trait named `Example` with associated type `{name}` \
-                             implemented for one of the types, you could use the fully-qualified \
-                             path",
-                        ),
-                        types
-                            .into_iter()
-                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
-                        Applicability::HasPlaceholders,
-                    );
-                }
-                (types, traits) => {
-                    let mut suggestions = vec![];
-                    for type_str in types {
-                        for trait_str in traits {
-                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
-                        }
-                    }
-                    err.span_suggestions(
-                        span,
-                        "use fully-qualified syntax",
-                        suggestions,
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-        let reported = err.emit();
-        self.set_tainted_by_errors(reported);
-        reported
-    }
-
     // Search for a bound on a type parameter which includes the associated item
     // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
     // This function will fail if there are no suitable bounds or there is
@@ -2471,8 +2329,6 @@
                     def_id,
                     &[],
                     &hir::PathSegment::invalid(),
-                    &GenericArgs::none(),
-                    true,
                     None,
                     ty::BoundConstness::NotConst,
                 );
@@ -2552,9 +2408,9 @@
 
     pub fn ty_of_arg(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
         match ty.kind {
-            hir::TyKind::Infer if expected_ty.is_some() => {
-                self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span);
-                expected_ty.unwrap()
+            hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
+                self.record_ty(ty.hir_id, expected_ty, ty.span);
+                expected_ty
             }
             _ => self.ast_ty_to_ty(ty),
         }
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index b9543c7..d97728c 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -17,7 +17,7 @@
 
 use super::AstConv;
 
-impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
+impl<'tcx> dyn AstConv<'tcx> + '_ {
     pub(super) fn conv_object_ty_poly_trait_ref(
         &self,
         span: Span,
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 1b8174d..d1fed13 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -381,11 +381,17 @@
     match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
         Ok(()) => {}
         Err(ty_err) => {
+            // Some types may be left "stranded" if they can't be reached
+            // from an astconv'd bound but they're mentioned in the HIR. This
+            // will happen, e.g., when a nested opaque is inside of a non-
+            // existent associated type, like `impl Trait<Missing = impl Trait>`.
+            // See <tests/ui/impl-trait/stranded-opaque.rs>.
             let ty_err = ty_err.to_string(tcx);
-            tcx.dcx().span_bug(
+            let guar = tcx.dcx().span_delayed_bug(
                 span,
                 format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
             );
+            return Err(guar);
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 3d80325..d5908cf 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -42,8 +42,7 @@
         if !def_id.is_local() {
             return None;
         }
-        let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
-        match tcx.hir_node(hir_id) {
+        match tcx.hir_node_by_def_id(def_id.expect_local()) {
             Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => {
                 generics.params.is_empty().not().then_some(generics.span)
             }
@@ -57,8 +56,7 @@
         if !def_id.is_local() {
             return None;
         }
-        let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
-        match tcx.hir_node(hir_id) {
+        match tcx.hir_node_by_def_id(def_id.expect_local()) {
             Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => {
                 Some(generics.where_clause_span)
             }
@@ -79,8 +77,7 @@
         if !def_id.is_local() {
             return None;
         }
-        let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
-        match tcx.hir_node(hir_id) {
+        match tcx.hir_node_by_def_id(def_id.expect_local()) {
             Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. }) => {
                 Some(fn_sig.decl.output.span())
             }
diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs
index b9dc5cb..f0c15a0 100644
--- a/compiler/rustc_hir_analysis/src/check/errs.rs
+++ b/compiler/rustc_hir_analysis/src/check/errs.rs
@@ -27,7 +27,7 @@
 
 /// Check for shared or mutable references of `static mut` inside statement
 pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
-    if let hir::StmtKind::Local(loc) = stmt.kind
+    if let hir::StmtKind::Let(loc) = stmt.kind
         && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
         && matches!(ba.0, rustc_ast::ByRef::Yes)
         && let Some(init) = loc.init
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index f5bfc6b..22afdda 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -130,7 +130,7 @@
 ) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
-    tcx.opt_hir_node_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
+    tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
         let body = tcx.hir().body(body_id);
         let mut visitor = ReturnsVisitor::default();
         visitor.visit_body(body);
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 2a4dd6b..3c26729 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -123,7 +123,7 @@
 
         for (i, statement) in blk.stmts.iter().enumerate() {
             match statement.kind {
-                hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => {
+                hir::StmtKind::Let(hir::Local { els: Some(els), .. }) => {
                     // Let-else has a special lexical structure for variables.
                     // First we take a checkpoint of the current scope context here.
                     let mut prev_cx = visitor.cx;
@@ -146,7 +146,7 @@
                     // From now on, we continue normally.
                     visitor.cx = prev_cx;
                 }
-                hir::StmtKind::Local(..) => {
+                hir::StmtKind::Let(..) => {
                     // Each declaration introduces a subscope for bindings
                     // introduced by the declaration; this subscope covers a
                     // suffix of the block. Each subscope in a block has the
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 09689b2..f525004 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -196,6 +196,7 @@
         hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item),
         hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item),
         hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item),
+        hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(),
     };
 
     if let Some(generics) = node.generics() {
@@ -1968,13 +1969,10 @@
             // Match the existing behavior.
             if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
                 let pred = self.normalize(span, None, pred);
-                let hir_node = tcx.opt_hir_node_by_def_id(self.body_def_id);
 
                 // only use the span of the predicate clause (#90869)
-
-                if let Some(hir::Generics { predicates, .. }) =
-                    hir_node.and_then(|node| node.generics())
-                {
+                let hir_node = tcx.hir_node_by_def_id(self.body_def_id);
+                if let Some(hir::Generics { predicates, .. }) = hir_node.generics() {
                     span = predicates
                         .iter()
                         // There seems to be no better way to find out which predicate we are in
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 10922d5..5cd6862 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -595,12 +595,14 @@
             tcx.ensure().type_of(def_id);
             tcx.ensure().impl_trait_header(def_id);
             tcx.ensure().predicates_of(def_id);
+            tcx.ensure().associated_items(def_id);
         }
         hir::ItemKind::Trait(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().trait_def(def_id);
             tcx.at(it.span).super_predicates_of(def_id);
             tcx.ensure().predicates_of(def_id);
+            tcx.ensure().associated_items(def_id);
         }
         hir::ItemKind::TraitAlias(..) => {
             tcx.ensure().generics_of(def_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 2675eac..6aae4aa 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -609,10 +609,8 @@
         return tcx.super_predicates_of(trait_def_id);
     };
 
-    let trait_hir_id = tcx.local_def_id_to_hir_id(trait_def_id);
-
-    let Node::Item(item) = tcx.hir_node(trait_hir_id) else {
-        bug!("trait_node_id {} is not an item", trait_hir_id);
+    let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else {
+        bug!("trait_def_id {trait_def_id:?} is not an item");
     };
 
     let (generics, bounds) = match item.kind {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 7936621..d1da2fa 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -262,6 +262,7 @@
             visitor.visit_impl_item(item)
         }
         hir::OwnerNode::Crate(_) => {}
+        hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(),
     }
 
     let mut rl = ResolveBoundVars::default();
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 598dba9..fd86f2d 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -108,8 +108,7 @@
                 .unwrap()
                 .0
                 .def_id;
-            let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
-            let ty = item_ctxt.ast_ty_to_ty(hir_ty);
+            let ty = ItemCtxt::new(tcx, item_def_id).to_ty(hir_ty);
 
             // Iterate through the generics of the projection to find the one that corresponds to
             // the def_id that this query was called with. We filter to only type and const args here
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index dcb01a1..b576591 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -371,11 +371,10 @@
             return mir_opaque_ty.ty;
         }
 
-        let scope = tcx.local_def_id_to_hir_id(owner_def_id);
-        debug!(?scope);
+        debug!(?owner_def_id);
         let mut locator = RpitConstraintChecker { def_id, tcx, found: mir_opaque_ty };
 
-        match tcx.hir_node(scope) {
+        match tcx.hir_node_by_def_id(owner_def_id) {
             Node::Item(it) => intravisit::walk_item(&mut locator, it),
             Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
             Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 8cf70fe..19ab204 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -100,19 +100,16 @@
 
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_middle::middle;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::util;
 use rustc_session::parse::feature_err;
-use rustc_span::{symbol::sym, Span, DUMMY_SP};
+use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 
-use astconv::{AstConv, OnlySelfBounds};
-use bounds::Bounds;
-use rustc_hir::def::DefKind;
-
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
@@ -222,31 +219,5 @@
     // def-ID that will be used to determine the traits/predicates in
     // scope. This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
-    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
-    item_cx.astconv().ast_ty_to_ty(hir_ty)
-}
-
-pub fn hir_trait_to_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    hir_trait: &hir::TraitRef<'tcx>,
-    self_ty: Ty<'tcx>,
-) -> Bounds<'tcx> {
-    // In case there are any projections, etc., find the "environment"
-    // def-ID that will be used to determine the traits/predicates in
-    // scope. This is derived from the enclosing item-like thing.
-    let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
-    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
-    let mut bounds = Bounds::default();
-    let _ = &item_cx.astconv().instantiate_poly_trait_ref(
-        hir_trait,
-        DUMMY_SP,
-        ty::BoundConstness::NotConst,
-        ty::ImplPolarity::Positive,
-        self_ty,
-        &mut bounds,
-        true,
-        OnlySelfBounds(false),
-    );
-
-    bounds
+    collect::ItemCtxt::new(tcx, env_def_id.def_id).to_ty(hir_ty)
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index b5bb063..e070db9 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -121,6 +121,7 @@
                 self.print_bounds(":", pred.bounds);
             }
             Node::ArrayLenInfer(_) => self.word("_"),
+            Node::AssocOpaqueTy(..) => unreachable!(),
             Node::Err(_) => self.word("/*ERROR*/"),
         }
     }
@@ -863,7 +864,7 @@
     fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
-            hir::StmtKind::Local(loc) => {
+            hir::StmtKind::Let(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)),
@@ -2306,7 +2307,7 @@
 /// seen the semicolon, and thus don't need another.
 fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
     match *stmt {
-        hir::StmtKind::Local(_) => true,
+        hir::StmtKind::Let(_) => true,
         hir::StmtKind::Item(_) => false,
         hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e),
         hir::StmtKind::Semi(..) => false,
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index c734338..4b33598 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -234,11 +234,8 @@
         }
 
         // Next, make sure that we have no type expectation.
-        let Some(ret) = self
-            .tcx
-            .opt_hir_node_by_def_id(self.body_id)
-            .and_then(|owner| owner.fn_decl())
-            .map(|decl| decl.output.span())
+        let Some(ret) =
+            self.tcx.hir_node_by_def_id(self.body_id).fn_decl().map(|decl| decl.output.span())
         else {
             return;
         };
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index c17af66..4bea4bb 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -780,7 +780,7 @@
         decl: &hir::FnDecl<'tcx>,
         closure_kind: hir::ClosureKind,
     ) -> ty::PolyFnSig<'tcx> {
-        let astconv: &dyn AstConv<'_> = self;
+        let astconv = self.astconv();
 
         trace!("decl = {:#?}", decl);
         debug!(?closure_kind);
@@ -985,7 +985,7 @@
         decl: &hir::FnDecl<'tcx>,
         guar: ErrorGuaranteed,
     ) -> ty::PolyFnSig<'tcx> {
-        let astconv: &dyn AstConv<'_> = self;
+        let astconv = self.astconv();
         let err_ty = Ty::new_error(self.tcx, guar);
 
         let supplied_arguments = decl.inputs.iter().map(|a| {
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 71da655..67ff412 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1071,7 +1071,7 @@
                     err.span_suggestion_verbose(
                         *span,
                         "use the type name directly",
-                        self.tcx.value_path_str_with_args(*alias_to, e_args),
+                        self.tcx.value_path_str_with_args(e_def.did(), e_args),
                         Applicability::MaybeIncorrect,
                     );
                 }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 7e19e57..1a142f2 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -890,21 +890,19 @@
 
         let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
 
-        if let Some(hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Fn(..),
-            span: encl_fn_span,
-            ..
-        }))
-        | Some(hir::Node::TraitItem(hir::TraitItem {
+        if let hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(..), span: encl_fn_span, ..
+        })
+        | hir::Node::TraitItem(hir::TraitItem {
             kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
             span: encl_fn_span,
             ..
-        }))
-        | Some(hir::Node::ImplItem(hir::ImplItem {
+        })
+        | hir::Node::ImplItem(hir::ImplItem {
             kind: hir::ImplItemKind::Fn(..),
             span: encl_fn_span,
             ..
-        })) = self.tcx.opt_hir_node_by_def_id(encl_item_id.def_id)
+        }) = self.tcx.hir_node_by_def_id(encl_item_id.def_id)
         {
             // We are inside a function body, so reporting "return statement
             // outside of function body" needs an explanation.
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index ba0383d..43e9554 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -371,11 +371,11 @@
 
     fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
         match stmt.kind {
-            hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => {
+            hir::StmtKind::Let(hir::Local { pat, init: Some(expr), els, .. }) => {
                 self.walk_local(expr, pat, *els, |_| {})
             }
 
-            hir::StmtKind::Local(_) => {}
+            hir::StmtKind::Let(_) => {}
 
             hir::StmtKind::Item(_) => {
                 // We don't visit nested items in this visitor,
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index aa8bbad..c16e941 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -4,8 +4,22 @@
     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
     unord::{UnordBag, UnordMap, UnordSet},
 };
+use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
+
+enum DivergingFallbackBehavior {
+    /// Always fallback to `()` (aka "always spontaneous decay")
+    FallbackToUnit,
+    /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
+    FallbackToNiko,
+    /// Always fallback to `!` (which should be equivalent to never falling back + not making
+    /// never-to-any coercions unless necessary)
+    FallbackToNever,
+    /// Don't fallback at all
+    NoFallback,
+}
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
     /// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
@@ -64,7 +78,9 @@
             return false;
         }
 
-        let diverging_fallback = self.calculate_diverging_fallback(&unresolved_variables);
+        let diverging_behavior = self.diverging_fallback_behavior();
+        let diverging_fallback =
+            self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior);
 
         // We do fallback in two passes, to try to generate
         // better error messages.
@@ -78,6 +94,32 @@
         fallback_occurred
     }
 
+    fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
+        let Some((mode, span)) = self
+            .tcx
+            .get_attr(CRATE_DEF_ID, sym::rustc_never_type_mode)
+            .map(|attr| (attr.value_str().unwrap(), attr.span))
+        else {
+            if self.tcx.features().never_type_fallback {
+                return DivergingFallbackBehavior::FallbackToNiko;
+            }
+
+            return DivergingFallbackBehavior::FallbackToUnit;
+        };
+
+        match mode {
+            sym::fallback_to_unit => DivergingFallbackBehavior::FallbackToUnit,
+            sym::fallback_to_niko => DivergingFallbackBehavior::FallbackToNiko,
+            sym::fallback_to_never => DivergingFallbackBehavior::FallbackToNever,
+            sym::no_fallback => DivergingFallbackBehavior::NoFallback,
+            _ => {
+                self.tcx.dcx().span_err(span, format!("unknown never type mode: `{mode}` (supported: `fallback_to_unit`, `fallback_to_niko`, `fallback_to_never` and `no_fallback`)"));
+
+                DivergingFallbackBehavior::FallbackToUnit
+            }
+        }
+    }
+
     fn fallback_effects(&self) -> bool {
         let unsolved_effects = self.unsolved_effects();
 
@@ -232,6 +274,7 @@
     fn calculate_diverging_fallback(
         &self,
         unresolved_variables: &[Ty<'tcx>],
+        behavior: DivergingFallbackBehavior,
     ) -> UnordMap<Ty<'tcx>, Ty<'tcx>> {
         debug!("calculate_diverging_fallback({:?})", unresolved_variables);
 
@@ -345,39 +388,61 @@
                 output: infer_var_infos.items().any(|info| info.output),
             };
 
-            if found_infer_var_info.self_in_trait && found_infer_var_info.output {
-                // This case falls back to () to ensure that the code pattern in
-                // tests/ui/never_type/fallback-closure-ret.rs continues to
-                // compile when never_type_fallback is enabled.
-                //
-                // This rule is not readily explainable from first principles,
-                // but is rather intended as a patchwork fix to ensure code
-                // which compiles before the stabilization of never type
-                // fallback continues to work.
-                //
-                // Typically this pattern is encountered in a function taking a
-                // closure as a parameter, where the return type of that closure
-                // (checked by `relationship.output`) is expected to implement
-                // some trait (checked by `relationship.self_in_trait`). This
-                // can come up in non-closure cases too, so we do not limit this
-                // rule to specifically `FnOnce`.
-                //
-                // When the closure's body is something like `panic!()`, the
-                // return type would normally be inferred to `!`. However, it
-                // needs to fall back to `()` in order to still compile, as the
-                // trait is specifically implemented for `()` but not `!`.
-                //
-                // For details on the requirements for these relationships to be
-                // set, see the relationship finding module in
-                // compiler/rustc_trait_selection/src/traits/relationships.rs.
-                debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
-                diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
-            } else if can_reach_non_diverging {
-                debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
-                diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
-            } else {
-                debug!("fallback to ! - all diverging: {:?}", diverging_vid);
-                diverging_fallback.insert(diverging_ty, Ty::new_diverging_default(self.tcx));
+            use DivergingFallbackBehavior::*;
+            match behavior {
+                FallbackToUnit => {
+                    debug!("fallback to () - legacy: {:?}", diverging_vid);
+                    diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
+                }
+                FallbackToNiko => {
+                    if found_infer_var_info.self_in_trait && found_infer_var_info.output {
+                        // This case falls back to () to ensure that the code pattern in
+                        // tests/ui/never_type/fallback-closure-ret.rs continues to
+                        // compile when never_type_fallback is enabled.
+                        //
+                        // This rule is not readily explainable from first principles,
+                        // but is rather intended as a patchwork fix to ensure code
+                        // which compiles before the stabilization of never type
+                        // fallback continues to work.
+                        //
+                        // Typically this pattern is encountered in a function taking a
+                        // closure as a parameter, where the return type of that closure
+                        // (checked by `relationship.output`) is expected to implement
+                        // some trait (checked by `relationship.self_in_trait`). This
+                        // can come up in non-closure cases too, so we do not limit this
+                        // rule to specifically `FnOnce`.
+                        //
+                        // When the closure's body is something like `panic!()`, the
+                        // return type would normally be inferred to `!`. However, it
+                        // needs to fall back to `()` in order to still compile, as the
+                        // trait is specifically implemented for `()` but not `!`.
+                        //
+                        // For details on the requirements for these relationships to be
+                        // set, see the relationship finding module in
+                        // compiler/rustc_trait_selection/src/traits/relationships.rs.
+                        debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
+                        diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
+                    } else if can_reach_non_diverging {
+                        debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
+                        diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
+                    } else {
+                        debug!("fallback to ! - all diverging: {:?}", diverging_vid);
+                        diverging_fallback.insert(diverging_ty, self.tcx.types.never);
+                    }
+                }
+                FallbackToNever => {
+                    debug!(
+                        "fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}",
+                        diverging_vid
+                    );
+                    diverging_fallback.insert(diverging_ty, self.tcx.types.never);
+                }
+                NoFallback => {
+                    debug!(
+                        "no fallback - `rustc_never_type_mode = \"no_fallback\"`: {:?}",
+                        diverging_vid
+                    );
+                }
             }
         }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a08582a..536d44a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1593,7 +1593,7 @@
         // Don't do all the complex logic below for `DeclItem`.
         match stmt.kind {
             hir::StmtKind::Item(..) => return,
-            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+            hir::StmtKind::Let(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
         }
 
         self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
@@ -1602,7 +1602,7 @@
         let old_diverges = self.diverges.replace(Diverges::Maybe);
 
         match stmt.kind {
-            hir::StmtKind::Local(l) => {
+            hir::StmtKind::Let(l) => {
                 self.check_decl_local(l);
             }
             // Ignore for now.
@@ -1765,7 +1765,7 @@
                                             [
                                                 hir::Stmt {
                                                     kind:
-                                                        hir::StmtKind::Local(hir::Local {
+                                                        hir::StmtKind::Let(hir::Local {
                                                             source:
                                                                 hir::LocalSource::AssignDesugar(_),
                                                             ..
@@ -2172,14 +2172,11 @@
                 // Try to find earlier invocations of this closure to find if the type mismatch
                 // is because of inference. If we find one, point at them.
                 let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
-                let node = self
-                    .tcx
-                    .opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id))
-                    .map(|hir_id| self.tcx.hir_node(hir_id));
-                match node {
-                    Some(hir::Node::Item(item)) => call_finder.visit_item(item),
-                    Some(hir::Node::TraitItem(item)) => call_finder.visit_trait_item(item),
-                    Some(hir::Node::ImplItem(item)) => call_finder.visit_impl_item(item),
+                let parent_def_id = self.tcx.hir().get_parent_item(call_expr.hir_id).def_id;
+                match self.tcx.hir_node_by_def_id(parent_def_id) {
+                    hir::Node::Item(item) => call_finder.visit_item(item),
+                    hir::Node::TraitItem(item) => call_finder.visit_trait_item(item),
+                    hir::Node::ImplItem(item) => call_finder.visit_impl_item(item),
                     _ => {}
                 }
                 let typeck = self.typeck_results.borrow();
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 5a1c7b0..3f6f4cc 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1599,7 +1599,7 @@
 
     fn is_local_statement(&self, id: hir::HirId) -> bool {
         let node = self.tcx.hir_node(id);
-        matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. }))
+        matches!(node, Node::Stmt(Stmt { kind: StmtKind::Let(..), .. }))
     }
 
     /// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 4c413e4..c5bbcc5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2221,7 +2221,7 @@
                 impl<'v> Visitor<'v> for LetVisitor {
                     type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
                     fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
-                        if let hir::StmtKind::Local(&hir::Local { pat, init, .. }) = ex.kind
+                        if let hir::StmtKind::Let(&hir::Local { pat, init, .. }) = ex.kind
                             && let Binding(_, _, ident, ..) = pat.kind
                             && ident.name == self.ident_name
                         {
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 211109b..be14f5b 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -217,7 +217,7 @@
                 bug!();
             };
             for stmt in block.stmts {
-                let hir::StmtKind::Local(hir::Local {
+                let hir::StmtKind::Let(hir::Local {
                     init: Some(init),
                     source: hir::LocalSource::AsyncFn,
                     pat,
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index dd9c16d..1462037 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -110,8 +110,9 @@
 use rustc_data_structures::{base_n, flock};
 use rustc_errors::ErrorGuaranteed;
 use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
+use rustc_session::config::CrateType;
+use rustc_session::output::{collect_crate_types, find_crate_name};
 use rustc_session::{Session, StableCrateId};
-use rustc_span::Symbol;
 
 use std::fs as std_fs;
 use std::io::{self, ErrorKind};
@@ -205,11 +206,7 @@
 /// The garbage collection will take care of it.
 ///
 /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
-pub(crate) fn prepare_session_directory(
-    sess: &Session,
-    crate_name: Symbol,
-    stable_crate_id: StableCrateId,
-) -> Result<(), ErrorGuaranteed> {
+pub(crate) fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuaranteed> {
     if sess.opts.incremental.is_none() {
         return Ok(());
     }
@@ -219,7 +216,7 @@
     debug!("prepare_session_directory");
 
     // {incr-comp-dir}/{crate-name-and-disambiguator}
-    let crate_dir = crate_path(sess, crate_name, stable_crate_id);
+    let crate_dir = crate_path(sess);
     debug!("crate-dir: {}", crate_dir.display());
     create_dir(sess, &crate_dir, "crate")?;
 
@@ -604,9 +601,18 @@
     Ok(UNIX_EPOCH + duration)
 }
 
-fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf {
+fn crate_path(sess: &Session) -> PathBuf {
     let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
 
+    let crate_name = find_crate_name(sess, &[]);
+    let crate_types = collect_crate_types(sess, &[]);
+    let stable_crate_id = StableCrateId::new(
+        crate_name,
+        crate_types.contains(&CrateType::Executable),
+        sess.opts.cg.metadata.clone(),
+        sess.cfg_version,
+    );
+
     let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE);
 
     let crate_name = format!("{crate_name}-{stable_crate_id}");
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 96bfe76..357f2ae 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -8,8 +8,8 @@
 use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::Decodable;
 use rustc_session::config::IncrementalStateAssertion;
-use rustc_session::{Session, StableCrateId};
-use rustc_span::{ErrorGuaranteed, Symbol};
+use rustc_session::Session;
+use rustc_span::ErrorGuaranteed;
 use std::path::{Path, PathBuf};
 
 use super::data::*;
@@ -190,13 +190,9 @@
 
 /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a
 /// new graph to an incremental session directory.
-pub fn setup_dep_graph(
-    sess: &Session,
-    crate_name: Symbol,
-    stable_crate_id: StableCrateId,
-) -> Result<DepGraph, ErrorGuaranteed> {
+pub fn setup_dep_graph(sess: &Session) -> Result<DepGraph, ErrorGuaranteed> {
     // `load_dep_graph` can only be called after `prepare_session_directory`.
-    prepare_session_directory(sess, crate_name, stable_crate_id)?;
+    prepare_session_directory(sess)?;
 
     let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess));
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 222c0a3..5d2a955 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2126,8 +2126,8 @@
         let TypeError::FixedArraySize(sz) = terr else {
             return None;
         };
-        let tykind = match self.tcx.opt_hir_node_by_def_id(trace.cause.body_id) {
-            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
+        let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => {
                 let body = hir.body(*body_id);
                 struct LetVisitor {
                     span: Span,
@@ -2139,7 +2139,7 @@
                         // the same span as the error and the type is specified.
                         if let hir::Stmt {
                             kind:
-                                hir::StmtKind::Local(hir::Local {
+                                hir::StmtKind::Let(hir::Local {
                                     init: Some(hir::Expr { span: init_span, .. }),
                                     ty: Some(array_ty),
                                     ..
@@ -2156,7 +2156,7 @@
                 }
                 LetVisitor { span }.visit_body(body).break_value()
             }
-            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }) => {
                 Some(&ty.peel_refs().kind)
             }
             _ => None,
@@ -2527,15 +2527,14 @@
                     .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
                     .map(|p| p.name)
                     .collect::<Vec<_>>();
-            if let Some(hir_id) = self.tcx.opt_local_def_id_to_hir_id(lifetime_scope) {
-                // consider late-bound lifetimes ...
-                used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(|p| {
-                    match p {
-                        ty::BoundVariableKind::Region(lt) => lt.get_name(),
-                        _ => None,
-                    }
-                }))
-            }
+            let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
+            // consider late-bound lifetimes ...
+            used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
+                |p| match p {
+                    ty::BoundVariableKind::Region(lt) => lt.get_name(),
+                    _ => None,
+                },
+            ));
             (b'a'..=b'z')
                 .map(|c| format!("'{}", c as char))
                 .find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
@@ -2554,6 +2553,7 @@
             hir::OwnerNode::ImplItem(i) => visitor.visit_impl_item(i),
             hir::OwnerNode::TraitItem(i) => visitor.visit_trait_item(i),
             hir::OwnerNode::Crate(_) => bug!("OwnerNode::Crate doesn't not have generics"),
+            hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(),
         }
 
         let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index afcb4a1..5036451 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -459,7 +459,7 @@
                 tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
                     if let Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
-                    }) = tcx.opt_hir_node_by_def_id(impl_did)?
+                    }) = tcx.hir_node_by_def_id(impl_did)
                         && trait_objects.iter().all(|did| {
                             // FIXME: we should check `self_ty` against the receiver
                             // type in the `UnifyReceiver` context, but for now, use
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index d14cabf..24eaff0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -804,23 +804,22 @@
     ) -> bool {
         let tcx = self.tcx;
 
-        let Some(hir_id) = body_owner_def_id.as_local() else {
+        let Some(def_id) = body_owner_def_id.as_local() else {
             return false;
         };
-        let Some(hir_id) = tcx.opt_local_def_id_to_hir_id(hir_id) else {
-            return false;
-        };
+
         // When `body_owner` is an `impl` or `trait` item, look in its associated types for
         // `expected` and point at it.
+        let hir_id = tcx.local_def_id_to_hir_id(def_id);
         let parent_id = tcx.hir().get_parent_item(hir_id);
-        let item = tcx.opt_hir_node_by_def_id(parent_id.def_id);
+        let item = tcx.hir_node_by_def_id(parent_id.def_id);
 
         debug!("expected_projection parent item {:?}", item);
 
         let param_env = tcx.param_env(body_owner_def_id);
 
         match item {
-            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. }) => {
                 // FIXME: account for `#![feature(specialization)]`
                 for item in &items[..] {
                     match item.kind {
@@ -845,10 +844,10 @@
                     }
                 }
             }
-            Some(hir::Node::Item(hir::Item {
+            hir::Node::Item(hir::Item {
                 kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
                 ..
-            })) => {
+            }) => {
                 for item in &items[..] {
                     if let hir::AssocItemKind::Type = item.kind {
                         let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 8cdf39b..9081fba 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -585,7 +585,7 @@
             }
 
             fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
-                if let hir::StmtKind::Local(hir::Local {
+                if let hir::StmtKind::Let(hir::Local {
                     span,
                     pat: hir::Pat { .. },
                     ty: None,
@@ -824,7 +824,7 @@
 
         let hir = self.tcx.hir();
         for stmt in blk.stmts.iter().rev() {
-            let hir::StmtKind::Local(local) = &stmt.kind else {
+            let hir::StmtKind::Let(local) = &stmt.kind else {
                 continue;
             };
             local.pat.walk(&mut find_compatible_candidates);
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index bd9fad8..47dfbc1 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -48,6 +48,3 @@
 
 interface_temps_dir_error =
     failed to find or create the directory specified by `--temps-dir`
-
-interface_unsupported_crate_type_for_target =
-    dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index f44ae70..a27f737 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -29,7 +29,7 @@
 /// This is a callback from `rustc_errors` as it cannot access the implicit state
 /// in `rustc_middle` otherwise. It is used when diagnostic messages are
 /// emitted and stores them in the current query, if there is one.
-fn track_diagnostic(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner)) {
+fn track_diagnostic<R>(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
     tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
             if let Some(diagnostics) = icx.diagnostics {
@@ -38,11 +38,11 @@
 
             // Diagnostics are tracked, we can ignore the dependency.
             let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
-            return tls::enter_context(&icx, move || (*f)(diagnostic));
+            tls::enter_context(&icx, move || (*f)(diagnostic))
+        } else {
+            // In any other case, invoke diagnostics anyway.
+            (*f)(diagnostic)
         }
-
-        // In any other case, invoke diagnostics anyway.
-        (*f)(diagnostic);
     })
 }
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index a9ab272..2929400 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -1,7 +1,5 @@
 use rustc_macros::Diagnostic;
-use rustc_session::config::CrateType;
 use rustc_span::{Span, Symbol};
-use rustc_target::spec::TargetTriple;
 
 use std::io;
 use std::path::Path;
@@ -91,13 +89,6 @@
 pub struct ProcMacroCratePanicAbort;
 
 #[derive(Diagnostic)]
-#[diag(interface_unsupported_crate_type_for_target)]
-pub struct UnsupportedCrateTypeForTarget<'a> {
-    pub crate_type: CrateType,
-    pub target_triple: &'a TargetTriple,
-}
-
-#[derive(Diagnostic)]
 #[diag(interface_multiple_output_types_adaption)]
 pub struct MultipleOutputTypesAdaption;
 
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index c221882..ee677a0 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -18,7 +18,7 @@
 use rustc_serialize::opaque::FileEncodeResult;
 use rustc_session::config::{self, CrateType, OutputFilenames, OutputType};
 use rustc_session::cstore::Untracked;
-use rustc_session::output::find_crate_name;
+use rustc_session::output::{collect_crate_types, find_crate_name};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use std::any::Any;
@@ -128,7 +128,7 @@
 
             // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
             let crate_name = find_crate_name(sess, &pre_configured_attrs);
-            let crate_types = util::collect_crate_types(sess, &pre_configured_attrs);
+            let crate_types = collect_crate_types(sess, &pre_configured_attrs);
             let stable_crate_id = StableCrateId::new(
                 crate_name,
                 crate_types.contains(&CrateType::Executable),
@@ -136,7 +136,7 @@
                 sess.cfg_version,
             );
             let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
-            let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?;
+            let dep_graph = setup_dep_graph(sess)?;
 
             let cstore = FreezeLock::new(Box::new(CStore::new(
                 self.compiler.codegen_backend.metadata_loader(),
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 829b00a..7d48f90 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -7,14 +7,15 @@
 use rustc_metadata::{load_symbol_from_dylib, DylibError};
 use rustc_parse::validate_attr;
 use rustc_session as session;
-use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes};
+use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes};
 use rustc_session::filesearch::sysroot_candidates;
 use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
-use rustc_session::{filesearch, output, Session};
+use rustc_session::{filesearch, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
 use rustc_target::spec::Target;
+use session::output::{categorize_crate_type, CRATE_TYPES};
 use session::EarlyDiagCtxt;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::path::{Path, PathBuf};
@@ -399,67 +400,6 @@
     }
 }
 
-const CRATE_TYPES: &[(Symbol, CrateType)] = &[
-    (sym::rlib, CrateType::Rlib),
-    (sym::dylib, CrateType::Dylib),
-    (sym::cdylib, CrateType::Cdylib),
-    (sym::lib, config::default_lib_output()),
-    (sym::staticlib, CrateType::Staticlib),
-    (sym::proc_dash_macro, CrateType::ProcMacro),
-    (sym::bin, CrateType::Executable),
-];
-
-fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
-    Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1)
-}
-
-pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<CrateType> {
-    // If we're generating a test executable, then ignore all other output
-    // styles at all other locations
-    if session.opts.test {
-        return vec![CrateType::Executable];
-    }
-
-    // Only check command line flags if present. If no types are specified by
-    // command line, then reuse the empty `base` Vec to hold the types that
-    // will be found in crate attributes.
-    // JUSTIFICATION: before wrapper fn is available
-    #[allow(rustc::bad_opt_access)]
-    let mut base = session.opts.crate_types.clone();
-    if base.is_empty() {
-        let attr_types = attrs.iter().filter_map(|a| {
-            if a.has_name(sym::crate_type)
-                && let Some(s) = a.value_str()
-            {
-                categorize_crate_type(s)
-            } else {
-                None
-            }
-        });
-        base.extend(attr_types);
-        if base.is_empty() {
-            base.push(output::default_output_for_target(session));
-        } else {
-            base.sort();
-            base.dedup();
-        }
-    }
-
-    base.retain(|crate_type| {
-        if output::invalid_output_for_target(session, *crate_type) {
-            session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
-                crate_type: *crate_type,
-                target_triple: &session.opts.target_triple,
-            });
-            false
-        } else {
-            true
-        }
-    });
-
-    base
-}
-
 fn multiple_output_types_to_stdout(
     output_types: &OutputTypes,
     single_output_file_is_stdout: bool,
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 595dc08..d1343e3 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -989,7 +989,7 @@
 impl EarlyLintPass for UnusedDocComment {
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
         let kind = match stmt.kind {
-            ast::StmtKind::Local(..) => "statements",
+            ast::StmtKind::Let(..) => "statements",
             // Disabled pending discussion in #78306
             ast::StmtKind::Item(..) => return,
             // expressions will be reported by `check_expr`.
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index d3d7698..506716e 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -356,7 +356,7 @@
         cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
         effective_visibilities: tcx.effective_visibilities(()),
-        last_node_with_lint_attrs: tcx.local_def_id_to_hir_id(module_def_id.into()),
+        last_node_with_lint_attrs: tcx.local_def_id_to_hir_id(module_def_id),
         generics: None,
         only_module: true,
     };
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index e89df1c..95f312a 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -103,11 +103,12 @@
         mut idx: LintStackIndex,
         aux: Option<&FxIndexMap<LintId, LevelAndSource>>,
     ) -> (Option<Level>, LintLevelSource) {
-        if let Some(specs) = aux {
-            if let Some(&(level, src)) = specs.get(&id) {
-                return (Some(level), src);
-            }
+        if let Some(specs) = aux
+            && let Some(&(level, src)) = specs.get(&id)
+        {
+            return (Some(level), src);
         }
+
         loop {
             let LintSet { ref specs, parent } = self.list[idx];
             if let Some(&(level, src)) = specs.get(&id) {
@@ -177,7 +178,7 @@
         // There is only something to do if there are attributes at all.
         [] => {}
         // Most of the time, there is only one attribute. Avoid fetching HIR in that case.
-        [(local_id, _)] => levels.add_id(HirId { owner, local_id: *local_id }),
+        &[(local_id, _)] => levels.add_id(HirId { owner, local_id }),
         // Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do
         // a standard visit.
         // FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's.
@@ -190,6 +191,7 @@
                 levels.add_id(hir::CRATE_HIR_ID);
                 levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID)
             }
+            hir::OwnerNode::AssocOpaqueTy(..) => unreachable!(),
         },
     }
 
@@ -643,63 +645,61 @@
         //
         // This means that this only errors if we're truly lowering the lint
         // level from forbid.
-        if self.lint_added_lints && level != Level::Forbid {
-            if let Level::Forbid = old_level {
-                // Backwards compatibility check:
-                //
-                // We used to not consider `forbid(lint_group)`
-                // as preventing `allow(lint)` for some lint `lint` in
-                // `lint_group`. For now, issue a future-compatibility
-                // warning for this case.
-                let id_name = id.lint.name_lower();
-                let fcw_warning = match old_src {
-                    LintLevelSource::Default => false,
-                    LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
-                    LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
-                };
-                debug!(
-                    "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
-                    fcw_warning,
-                    self.current_specs(),
-                    old_src,
-                    id_name
-                );
-                let sub = match old_src {
-                    LintLevelSource::Default => {
-                        OverruledAttributeSub::DefaultSource { id: id.to_string() }
-                    }
-                    LintLevelSource::Node { span, reason, .. } => {
-                        OverruledAttributeSub::NodeSource { span, reason }
-                    }
-                    LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource,
-                };
-                if !fcw_warning {
-                    self.sess.dcx().emit_err(OverruledAttribute {
-                        span: src.span(),
+        if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
+            // Backwards compatibility check:
+            //
+            // We used to not consider `forbid(lint_group)`
+            // as preventing `allow(lint)` for some lint `lint` in
+            // `lint_group`. For now, issue a future-compatibility
+            // warning for this case.
+            let id_name = id.lint.name_lower();
+            let fcw_warning = match old_src {
+                LintLevelSource::Default => false,
+                LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
+                LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+            };
+            debug!(
+                "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
+                fcw_warning,
+                self.current_specs(),
+                old_src,
+                id_name
+            );
+            let sub = match old_src {
+                LintLevelSource::Default => {
+                    OverruledAttributeSub::DefaultSource { id: id.to_string() }
+                }
+                LintLevelSource::Node { span, reason, .. } => {
+                    OverruledAttributeSub::NodeSource { span, reason }
+                }
+                LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource,
+            };
+            if !fcw_warning {
+                self.sess.dcx().emit_err(OverruledAttribute {
+                    span: src.span(),
+                    overruled: src.span(),
+                    lint_level: level.as_str(),
+                    lint_source: src.name(),
+                    sub,
+                });
+            } else {
+                self.emit_span_lint(
+                    FORBIDDEN_LINT_GROUPS,
+                    src.span().into(),
+                    OverruledAttributeLint {
                         overruled: src.span(),
                         lint_level: level.as_str(),
                         lint_source: src.name(),
                         sub,
-                    });
-                } else {
-                    self.emit_span_lint(
-                        FORBIDDEN_LINT_GROUPS,
-                        src.span().into(),
-                        OverruledAttributeLint {
-                            overruled: src.span(),
-                            lint_level: level.as_str(),
-                            lint_source: src.name(),
-                            sub,
-                        },
-                    );
-                }
+                    },
+                );
+            }
 
-                // Retain the forbid lint level, unless we are
-                // issuing a FCW. In the FCW case, we want to
-                // respect the new setting.
-                if !fcw_warning {
-                    return;
-                }
+            // Retain the forbid lint level, unless we are
+            // issuing a FCW. In the FCW case, we want to
+            // respect the new setting.
+            if !fcw_warning {
+                return;
             }
         }
 
@@ -770,15 +770,15 @@
 
             let Some(mut metas) = attr.meta_item_list() else { continue };
 
-            if metas.is_empty() {
+            // Check whether `metas` is empty, and get its last element.
+            let Some(tail_li) = metas.last() else {
                 // This emits the unused_attributes lint for `#[level()]`
                 continue;
-            }
+            };
 
             // Before processing the lint names, look for a reason (RFC 2383)
             // at the end.
             let mut reason = None;
-            let tail_li = &metas[metas.len() - 1];
             if let Some(item) = tail_li.meta_item() {
                 match item.kind {
                     ast::MetaItemKind::Word => {} // actual lint names handled later
@@ -834,21 +834,16 @@
                 let meta_item = match li {
                     ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item,
                     _ => {
-                        if let Some(item) = li.meta_item() {
-                            if let ast::MetaItemKind::NameValue(_) = item.kind {
-                                if item.path == sym::reason {
-                                    sess.dcx().emit_err(MalformedAttribute {
-                                        span: sp,
-                                        sub: MalformedAttributeSub::ReasonMustComeLast(sp),
-                                    });
-                                    continue;
-                                }
-                            }
-                        }
-                        sess.dcx().emit_err(MalformedAttribute {
-                            span: sp,
-                            sub: MalformedAttributeSub::BadAttributeArgument(sp),
-                        });
+                        let sub = if let Some(item) = li.meta_item()
+                            && let ast::MetaItemKind::NameValue(_) = item.kind
+                            && item.path == sym::reason
+                        {
+                            MalformedAttributeSub::ReasonMustComeLast(sp)
+                        } else {
+                            MalformedAttributeSub::BadAttributeArgument(sp)
+                        };
+
+                        sess.dcx().emit_err(MalformedAttribute { span: sp, sub });
                         continue;
                     }
                 };
@@ -987,11 +982,7 @@
                     }
 
                     CheckLintNameResult::NoLint(suggestion) => {
-                        let name = if let Some(tool_ident) = tool_ident {
-                            format!("{}::{}", tool_ident.name, name)
-                        } else {
-                            name.to_string()
-                        };
+                        let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
                         let suggestion = suggestion.map(|(replace, from_rustc)| {
                             UnknownLintSuggestion::WithSpan { suggestion: sp, replace, from_rustc }
                         });
@@ -1005,27 +996,24 @@
                 if let CheckLintNameResult::Renamed(new_name) = lint_result {
                     // Ignore any errors or warnings that happen because the new name is inaccurate
                     // NOTE: `new_name` already includes the tool name, so we don't have to add it again.
-                    if let CheckLintNameResult::Ok(ids) =
+                    let CheckLintNameResult::Ok(ids) =
                         self.store.check_lint_name(&new_name, None, self.registered_tools)
-                    {
-                        let src = LintLevelSource::Node {
-                            name: Symbol::intern(&new_name),
-                            span: sp,
-                            reason,
-                        };
-                        for &id in ids {
-                            if self.check_gated_lint(id, attr.span, false) {
-                                self.insert_spec(id, (level, src));
-                            }
-                        }
-                        if let Level::Expect(expect_id) = level {
-                            self.provider.push_expectation(
-                                expect_id,
-                                LintExpectation::new(reason, sp, false, tool_name),
-                            );
-                        }
-                    } else {
+                    else {
                         panic!("renamed lint does not exist: {new_name}");
+                    };
+
+                    let src =
+                        LintLevelSource::Node { name: Symbol::intern(&new_name), span: sp, reason };
+                    for &id in ids {
+                        if self.check_gated_lint(id, attr.span, false) {
+                            self.insert_spec(id, (level, src));
+                        }
+                    }
+                    if let Level::Expect(expect_id) = level {
+                        self.provider.push_expectation(
+                            expect_id,
+                            LintExpectation::new(reason, sp, false, tool_name),
+                        );
                     }
                 }
             }
@@ -1058,38 +1046,44 @@
     /// Returns `true` if the lint's feature is enabled.
     #[track_caller]
     fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
-        if let Some(feature) = lint_id.lint.feature_gate {
-            if !self.features.active(feature) {
-                if self.lint_added_lints {
-                    let lint = builtin::UNKNOWN_LINTS;
-                    let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
-                    // FIXME: make this translatable
-                    #[allow(rustc::diagnostic_outside_of_impl)]
-                    #[allow(rustc::untranslatable_diagnostic)]
-                    lint_level(
-                        self.sess,
+        let feature = if let Some(feature) = lint_id.lint.feature_gate
+            && !self.features.active(feature)
+        {
+            // Lint is behind a feature that is not enabled; eventually return false.
+            feature
+        } else {
+            // Lint is ungated or its feature is enabled; exit early.
+            return true;
+        };
+
+        if self.lint_added_lints {
+            let lint = builtin::UNKNOWN_LINTS;
+            let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
+            // FIXME: make this translatable
+            #[allow(rustc::diagnostic_outside_of_impl)]
+            #[allow(rustc::untranslatable_diagnostic)]
+            lint_level(
+                self.sess,
+                lint,
+                level,
+                src,
+                Some(span.into()),
+                fluent::lint_unknown_gated_lint,
+                |lint| {
+                    lint.arg("name", lint_id.lint.name_lower());
+                    lint.note(fluent::lint_note);
+                    rustc_session::parse::add_feature_diagnostics_for_issue(
                         lint,
-                        level,
-                        src,
-                        Some(span.into()),
-                        fluent::lint_unknown_gated_lint,
-                        |lint| {
-                            lint.arg("name", lint_id.lint.name_lower());
-                            lint.note(fluent::lint_note);
-                            rustc_session::parse::add_feature_diagnostics_for_issue(
-                                lint,
-                                &self.sess,
-                                feature,
-                                GateIssue::Language,
-                                lint_from_cli,
-                            );
-                        },
+                        &self.sess,
+                        feature,
+                        GateIssue::Language,
+                        lint_from_cli,
                     );
-                }
-                return false;
-            }
+                },
+            );
         }
-        true
+
+        false
     }
 
     /// Find the lint level for a lint.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 5d36a8b..51fe08d 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -561,10 +561,11 @@
         ty::Float(t) => {
             let is_infinite = match lit.node {
                 ast::LitKind::Float(v, _) => match t {
-                    ty::FloatTy::F16 => unimplemented!("f16_f128"),
+                    // FIXME(f16_f128): add this check once we have library support
+                    ty::FloatTy::F16 => Ok(false),
                     ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
                     ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
-                    ty::FloatTy::F128 => unimplemented!("f16_f128"),
+                    ty::FloatTy::F128 => Ok(false),
                 },
                 _ => bug!(),
             };
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index f84d1c6..3e10879 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -914,7 +914,7 @@
 
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
         match s.kind {
-            StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
+            StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
                 if let Some((init, els)) = local.kind.init_else_opt() {
                     let ctx = match els {
                         None => UnusedDelimsCtx::AssignedValue,
@@ -1189,7 +1189,7 @@
     }
 
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
-        if let StmtKind::Local(ref local) = s.kind {
+        if let StmtKind::Let(ref local) = s.kind {
             self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false));
         }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 20e492d..6506aa3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -557,6 +557,7 @@
     /// fn main() {
     ///     use foo::bar;
     ///     foo::bar();
+    ///     bar();
     /// }
     /// ```
     ///
@@ -704,6 +705,20 @@
     /// `PhantomData`.
     ///
     /// Otherwise consider removing the unused code.
+    ///
+    /// ### Limitations
+    ///
+    /// Removing fields that are only used for side-effects and never
+    /// read will result in behavioral changes. Examples of this
+    /// include:
+    ///
+    /// - If a field's value performs an action when it is dropped.
+    /// - If a field's type does not implement an auto trait
+    ///   (e.g. `Send`, `Sync`, `Unpin`).
+    ///
+    /// For side-effects from dropping field values, this lint should
+    /// be allowed on those fields. For side-effects from containing
+    /// field types, `PhantomData` should be used.
     pub DEAD_CODE,
     Warn,
     "detect unused, unexported items"
@@ -4341,7 +4356,6 @@
     pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
     Warn,
     "unrecognized or malformed diagnostic attribute",
-    @feature_gate = sym::diagnostic_namespace;
 }
 
 declare_lint! {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 2622638..d8cfcea 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1339,8 +1339,8 @@
             is_doc_hidden: false,
         };
         let attr_iter = tcx
-            .opt_local_def_id_to_hir_id(def_id)
-            .map_or(Default::default(), |hir_id| tcx.hir().attrs(hir_id))
+            .hir()
+            .attrs(tcx.local_def_id_to_hir_id(def_id))
             .iter()
             .filter(|attr| analyze_attr(attr, &mut state));
 
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index a532635..c904272 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -115,6 +115,7 @@
             [] features: rustc_feature::Features,
             [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
             [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
+            [] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
         ]);
     )
 }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index c05da36..5043bd8 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -158,23 +158,15 @@
         self.hir_owner_nodes(owner_id).node()
     }
 
-    /// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found.
-    #[inline]
-    pub fn opt_hir_node_by_def_id(self, id: LocalDefId) -> Option<Node<'tcx>> {
-        Some(self.hir_node(self.opt_local_def_id_to_hir_id(id)?))
-    }
-
     /// Retrieves the `hir::Node` corresponding to `id`.
     pub fn hir_node(self, id: HirId) -> Node<'tcx> {
         self.hir_owner_nodes(id.owner).nodes[id.local_id].node
     }
 
-    /// Retrieves the `hir::Node` corresponding to `id`, panicking if it cannot be found.
+    /// Retrieves the `hir::Node` corresponding to `id`.
     #[inline]
-    #[track_caller]
     pub fn hir_node_by_def_id(self, id: LocalDefId) -> Node<'tcx> {
-        self.opt_hir_node_by_def_id(id)
-            .unwrap_or_else(|| bug!("couldn't find HIR node for def id {id:?}"))
+        self.hir_node(self.local_def_id_to_hir_id(id))
     }
 
     /// Returns `HirId` of the parent HIR node of node with this `hir_id`.
@@ -241,8 +233,7 @@
     }
 
     pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local()
-            .and_then(|id| Some(self.tcx.hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?)))
+        id.as_local().map(|id| self.tcx.hir_node_by_def_id(id))
     }
 
     pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
@@ -306,7 +297,7 @@
     /// Given a `LocalDefId`, returns the `BodyId` associated with it,
     /// if the node is a body owner, otherwise returns `None`.
     pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
-        let node = self.tcx.opt_hir_node_by_def_id(id)?;
+        let node = self.tcx.hir_node_by_def_id(id);
         let (_, body_id) = associated_body(node)?;
         Some(body_id)
     }
@@ -655,7 +646,7 @@
                 | Node::ForeignItem(_)
                 | Node::TraitItem(_)
                 | Node::ImplItem(_)
-                | Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
+                | Node::Stmt(Stmt { kind: StmtKind::Let(_), .. }) => break,
                 Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
                     return Some(expr);
                 }
@@ -963,6 +954,7 @@
             Node::Crate(item) => item.spans.inner_span,
             Node::WhereBoundPredicate(pred) => pred.span,
             Node::ArrayLenInfer(inf) => inf.span,
+            Node::AssocOpaqueTy(..) => unreachable!(),
             Node::Err(span) => *span,
         }
     }
@@ -1227,6 +1219,7 @@
         Node::Crate(..) => String::from("(root_crate)"),
         Node::WhereBoundPredicate(_) => node_str("where bound predicate"),
         Node::ArrayLenInfer(_) => node_str("array len infer"),
+        Node::AssocOpaqueTy(..) => unreachable!(),
         Node::Err(_) => node_str("error"),
     }
 }
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 4ef9bc1..f9fa8ac 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -8,6 +8,9 @@
 
 use crate::query::Providers;
 use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
@@ -121,18 +124,40 @@
         self.opt_parent(def_id.into())
             .is_some_and(|parent| matches!(self.def_kind(parent), DefKind::ForeignMod))
     }
+
+    pub fn hash_owner_nodes(
+        self,
+        node: OwnerNode<'_>,
+        bodies: &SortedMap<ItemLocalId, &Body<'_>>,
+        attrs: &SortedMap<ItemLocalId, &[rustc_ast::Attribute]>,
+    ) -> (Option<Fingerprint>, Option<Fingerprint>) {
+        if self.needs_crate_hash() {
+            self.with_stable_hashing_context(|mut hcx| {
+                let mut stable_hasher = StableHasher::new();
+                node.hash_stable(&mut hcx, &mut stable_hasher);
+                // Bodies are stored out of line, so we need to pull them explicitly in the hash.
+                bodies.hash_stable(&mut hcx, &mut stable_hasher);
+                let h1 = stable_hasher.finish();
+
+                let mut stable_hasher = StableHasher::new();
+                attrs.hash_stable(&mut hcx, &mut stable_hasher);
+                let h2 = stable_hasher.finish();
+                (Some(h1), Some(h2))
+            })
+        } else {
+            (None, None)
+        }
+    }
 }
 
 pub fn provide(providers: &mut Providers) {
     providers.hir_crate_items = map::hir_crate_items;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
-    providers.opt_local_def_id_to_hir_id = |tcx, def_id| {
-        Some(match tcx.hir_crate(()).owners[def_id] {
-            MaybeOwner::Owner(_) => HirId::make_owner(def_id),
-            MaybeOwner::NonOwner(hir_id) => hir_id,
-            MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
-        })
+    providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
+        MaybeOwner::Owner(_) => HirId::make_owner(def_id),
+        MaybeOwner::NonOwner(hir_id) => hir_id,
+        MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
     };
     providers.opt_hir_owner_nodes =
         |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index 8588ae2..b984df3 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -6,6 +6,7 @@
 use crate::mir;
 use crate::query::TyCtxtAt;
 use crate::ty::{Ty, TyCtxt};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::DUMMY_SP;
 
 macro_rules! declare_hooks {
@@ -70,4 +71,10 @@
 
     /// Getting a &core::panic::Location referring to a span.
     hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue<'tcx>;
+
+    /// Returns `true` if this def is a function-like thing that is eligible for
+    /// coverage instrumentation under `-Cinstrument-coverage`.
+    ///
+    /// (Eligible functions might nevertheless be skipped for other reasons.)
+    hook is_eligible_for_coverage(key: LocalDefId) -> bool;
 }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 18e198e..645a417 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -2,11 +2,20 @@
 
 use rustc_index::IndexVec;
 use rustc_macros::HashStable;
-use rustc_span::Symbol;
+use rustc_span::{Span, Symbol};
 
 use std::fmt::{self, Debug, Formatter};
 
 rustc_index::newtype_index! {
+    /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR
+    /// lowering, so that those blocks can be identified later.
+    #[derive(HashStable)]
+    #[encodable]
+    #[debug_format = "BlockMarkerId({})"]
+    pub struct BlockMarkerId {}
+}
+
+rustc_index::newtype_index! {
     /// ID of a coverage counter. Values ascend from 0.
     ///
     /// Before MIR inlining, counter IDs are local to their enclosing function.
@@ -83,6 +92,12 @@
     /// codegen.
     SpanMarker,
 
+    /// Marks its enclosing basic block with an ID that can be referred to by
+    /// side data in [`BranchInfo`].
+    ///
+    /// Has no effect during codegen.
+    BlockMarker { id: BlockMarkerId },
+
     /// Marks the point in MIR control flow represented by a coverage counter.
     ///
     /// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR.
@@ -107,6 +122,7 @@
         use CoverageKind::*;
         match self {
             SpanMarker => write!(fmt, "SpanMarker"),
+            BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()),
             CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()),
             ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()),
         }
@@ -163,14 +179,18 @@
 pub enum MappingKind {
     /// Associates a normal region of code with a counter/expression/zero.
     Code(CovTerm),
+    /// Associates a branch region with separate counters for true and false.
+    Branch { true_term: CovTerm, false_term: CovTerm },
 }
 
 impl MappingKind {
     /// Iterator over all coverage terms in this mapping kind.
     pub fn terms(&self) -> impl Iterator<Item = CovTerm> {
-        let one = |a| std::iter::once(a);
+        let one = |a| std::iter::once(a).chain(None);
+        let two = |a, b| std::iter::once(a).chain(Some(b));
         match *self {
             Self::Code(term) => one(term),
+            Self::Branch { true_term, false_term } => two(true_term, false_term),
         }
     }
 
@@ -179,6 +199,9 @@
     pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self {
         match *self {
             Self::Code(term) => Self::Code(map_fn(term)),
+            Self::Branch { true_term, false_term } => {
+                Self::Branch { true_term: map_fn(true_term), false_term: map_fn(false_term) }
+            }
         }
     }
 }
@@ -202,3 +225,22 @@
     pub expressions: IndexVec<ExpressionId, Expression>,
     pub mappings: Vec<Mapping>,
 }
+
+/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR.
+#[derive(Clone, Debug)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub struct BranchInfo {
+    /// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was
+    /// injected into the MIR body. This makes it possible to allocate per-ID
+    /// data structures without having to scan the entire body first.
+    pub num_block_markers: usize,
+    pub branch_spans: Vec<BranchSpan>,
+}
+
+#[derive(Clone, Debug)]
+#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub struct BranchSpan {
+    pub span: Span,
+    pub true_marker: BlockMarkerId,
+    pub false_marker: BlockMarkerId,
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index e937c17..24d4a79 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -3,7 +3,7 @@
 use either::{Either, Left, Right};
 
 use rustc_apfloat::{
-    ieee::{Double, Single},
+    ieee::{Double, Half, Quad, Single},
     Float,
 };
 use rustc_macros::HashStable;
@@ -202,6 +202,11 @@
     }
 
     #[inline]
+    pub fn from_f16(f: Half) -> Self {
+        Scalar::Int(f.into())
+    }
+
+    #[inline]
     pub fn from_f32(f: Single) -> Self {
         Scalar::Int(f.into())
     }
@@ -211,6 +216,11 @@
         Scalar::Int(f.into())
     }
 
+    #[inline]
+    pub fn from_f128(f: Quad) -> Self {
+        Scalar::Int(f.into())
+    }
+
     /// This is almost certainly not the method you want!  You should dispatch on the type
     /// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed.
     ///
@@ -423,6 +433,11 @@
     }
 
     #[inline]
+    pub fn to_f16(self) -> InterpResult<'tcx, Half> {
+        self.to_float()
+    }
+
+    #[inline]
     pub fn to_f32(self) -> InterpResult<'tcx, Single> {
         self.to_float()
     }
@@ -431,4 +446,9 @@
     pub fn to_f64(self) -> InterpResult<'tcx, Double> {
         self.to_float()
     }
+
+    #[inline]
+    pub fn to_f128(self) -> InterpResult<'tcx, Quad> {
+        self.to_float()
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index b71c614..d57ffc0 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -403,6 +403,12 @@
 
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 
+    /// Branch coverage information collected during MIR building, to be used by
+    /// the `InstrumentCoverage` pass.
+    ///
+    /// Only present if branch coverage is enabled and this function is eligible.
+    pub coverage_branch_info: Option<Box<coverage::BranchInfo>>,
+
     /// Per-function coverage information added by the `InstrumentCoverage`
     /// pass, to be used in conjunction with the coverage statements injected
     /// into this body's blocks.
@@ -450,6 +456,7 @@
             is_polymorphic: false,
             injection_phase: None,
             tainted_by_errors,
+            coverage_branch_info: None,
             function_coverage_info: None,
         };
         body.is_polymorphic = body.has_non_region_param();
@@ -479,6 +486,7 @@
             is_polymorphic: false,
             injection_phase: None,
             tainted_by_errors: None,
+            coverage_branch_info: None,
             function_coverage_info: None,
         };
         body.is_polymorphic = body.has_non_region_param();
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 8ae65f3..94751c4 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -461,6 +461,9 @@
     // Add an empty line before the first block is printed.
     writeln!(w)?;
 
+    if let Some(branch_info) = &body.coverage_branch_info {
+        write_coverage_branch_info(branch_info, w)?;
+    }
     if let Some(function_coverage_info) = &body.function_coverage_info {
         write_function_coverage_info(function_coverage_info, w)?;
     }
@@ -468,6 +471,25 @@
     Ok(())
 }
 
+fn write_coverage_branch_info(
+    branch_info: &coverage::BranchInfo,
+    w: &mut dyn io::Write,
+) -> io::Result<()> {
+    let coverage::BranchInfo { branch_spans, .. } = branch_info;
+
+    for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans {
+        writeln!(
+            w,
+            "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
+        )?;
+    }
+    if !branch_spans.is_empty() {
+        writeln!(w)?;
+    }
+
+    Ok(())
+}
+
 fn write_function_coverage_info(
     function_coverage_info: &coverage::FunctionCoverageInfo,
     w: &mut dyn io::Write,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 83ded58..865299e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -174,10 +174,8 @@
         cache_on_disk_if { true }
     }
 
-    /// Gives access to the HIR ID for the given `LocalDefId` owner `key` if any.
-    ///
-    /// Definitions that were generated with no HIR, would be fed to return `None`.
-    query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option<hir::HirId>{
+    /// Returns HIR ID for the given `LocalDefId`.
+    query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
         desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key) }
         feedable
     }
@@ -196,6 +194,7 @@
     /// Avoid calling this query directly.
     query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
         desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
+        feedable
     }
 
     /// Gives access to the HIR attributes inside the HIR owner `key`.
@@ -204,6 +203,7 @@
     /// Avoid calling this query directly.
     query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
         desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
+        feedable
     }
 
     /// Given the def_id of a const-generic parameter, computes the associated default const
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 74b47d8..96a6188 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -321,9 +321,13 @@
     Cast {
         source: ExprId,
     },
+    /// Forces its contents to be treated as a value expression, not a place
+    /// expression. This is inserted in some places where an operation would
+    /// otherwise be erased completely (e.g. some no-op casts), but we still
+    /// need to ensure that its operand is treated as a value and not a place.
     Use {
         source: ExprId,
-    }, // Use a lexpr to get a vexpr.
+    },
     /// A coercion from `!` to any type.
     NeverToAny {
         source: ExprId,
@@ -338,6 +342,13 @@
     Loop {
         body: ExprId,
     },
+    /// Special expression representing the `let` part of an `if let` or similar construct
+    /// (including `if let` guards in match arms, and let-chains formed by `&&`).
+    ///
+    /// This isn't considered a real expression in surface Rust syntax, so it can
+    /// only appear in specific situations, such as within the condition of an `if`.
+    ///
+    /// (Not to be confused with [`StmtKind::Let`], which is a normal `let` statement.)
     Let {
         expr: ExprId,
         pat: Box<Pat<'tcx>>,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index aea5865..a04bd63 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -618,6 +618,7 @@
     OpaqueTypeAutoTraitLeakageUnknown(DefId),
 }
 
+// FIXME(@lcnr): The `Binder` here should be unnecessary. Just use `TraitRef` instead.
 #[derive(Clone, Debug, TypeVisitable)]
 pub struct SignatureMismatchData<'tcx> {
     pub found_trait_ref: ty::PolyTraitRef<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index a70e016..71d7dfd 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -1,4 +1,4 @@
-use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_apfloat::Float;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -370,6 +370,11 @@
     }
 
     #[inline]
+    pub fn try_to_f16(self) -> Result<Half, Size> {
+        self.try_to_float()
+    }
+
+    #[inline]
     pub fn try_to_f32(self) -> Result<Single, Size> {
         self.try_to_float()
     }
@@ -378,6 +383,11 @@
     pub fn try_to_f64(self) -> Result<Double, Size> {
         self.try_to_float()
     }
+
+    #[inline]
+    pub fn try_to_f128(self) -> Result<Quad, Size> {
+        self.try_to_float()
+    }
 }
 
 macro_rules! from {
@@ -450,6 +460,22 @@
     }
 }
 
+impl From<Half> for ScalarInt {
+    #[inline]
+    fn from(f: Half) -> Self {
+        // We trust apfloat to give us properly truncated data.
+        Self { data: f.to_bits(), size: NonZero::new((Half::BITS / 8) as u8).unwrap() }
+    }
+}
+
+impl TryFrom<ScalarInt> for Half {
+    type Error = Size;
+    #[inline]
+    fn try_from(int: ScalarInt) -> Result<Self, Size> {
+        int.to_bits(Size::from_bytes(2)).map(Self::from_bits)
+    }
+}
+
 impl From<Single> for ScalarInt {
     #[inline]
     fn from(f: Single) -> Self {
@@ -482,6 +508,22 @@
     }
 }
 
+impl From<Quad> for ScalarInt {
+    #[inline]
+    fn from(f: Quad) -> Self {
+        // We trust apfloat to give us properly truncated data.
+        Self { data: f.to_bits(), size: NonZero::new((Quad::BITS / 8) as u8).unwrap() }
+    }
+}
+
+impl TryFrom<ScalarInt> for Quad {
+    type Error = Size;
+    #[inline]
+    fn try_from(int: ScalarInt) -> Result<Self, Size> {
+        int.to_bits(Size::from_bytes(16)).map(Self::from_bits)
+    }
+}
+
 impl fmt::Debug for ScalarInt {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Dispatch to LowerHex below.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c415c06..17ba97c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -589,6 +589,11 @@
     pub fn def_id(&self) -> LocalDefId {
         self.key
     }
+
+    // Caller must ensure that `self.key` ID is indeed an owner.
+    pub fn feed_owner_id(&self) -> TyCtxtFeed<'tcx, hir::OwnerId> {
+        TyCtxtFeed { tcx: self.tcx, key: hir::OwnerId { def_id: self.key } }
+    }
 }
 
 /// The central data structure of the compiler. It stores references
@@ -1260,11 +1265,9 @@
             break (scope, ty::BrNamed(def_id.into(), self.item_name(def_id.into())));
         };
 
-        let is_impl_item = match self.opt_hir_node_by_def_id(suitable_region_binding_scope) {
-            Some(Node::Item(..) | Node::TraitItem(..)) => false,
-            Some(Node::ImplItem(..)) => {
-                self.is_bound_region_in_impl_item(suitable_region_binding_scope)
-            }
+        let is_impl_item = match self.hir_node_by_def_id(suitable_region_binding_scope) {
+            Node::Item(..) | Node::TraitItem(..) => false,
+            Node::ImplItem(..) => self.is_bound_region_in_impl_item(suitable_region_binding_scope),
             _ => false,
         };
 
@@ -2350,10 +2353,6 @@
         self.intrinsic_raw(def_id)
     }
 
-    pub fn local_def_id_to_hir_id(self, local_def_id: LocalDefId) -> HirId {
-        self.opt_local_def_id_to_hir_id(local_def_id).unwrap()
-    }
-
     pub fn next_trait_solver_globally(self) -> bool {
         self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally)
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index c8fb116..4b01564 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -405,6 +405,7 @@
     ::rustc_hir::HirId,
     ::rustc_hir::MatchSource,
     ::rustc_target::asm::InlineAsmRegOrRegClass,
+    crate::mir::coverage::BlockMarkerId,
     crate::mir::coverage::CounterId,
     crate::mir::coverage::ExpressionId,
     crate::mir::Local,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index cac12e5..11065b2 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2436,8 +2436,9 @@
             },
 
             // "Bound" types appear in canonical queries when the
-            // closure type is not yet known
-            Bound(..) | Param(_) | Infer(_) => None,
+            // closure type is not yet known, and `Placeholder` and `Param`
+            // may be encountered in generic `AsyncFnKindHelper` goals.
+            Bound(..) | Placeholder(_) | Param(_) | Infer(_) => None,
 
             Error(_) => Some(ty::ClosureKind::Fn),
 
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 8a6ccdb..1de691f 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -24,7 +24,7 @@
 
 mir_build_borrow_of_moved_value = borrow of moved value
     .label = value moved into `{$name}` here
-    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+    .occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
     .value_borrowed_label = value borrowed here after move
     .suggestion = borrow this binding in the pattern to avoid moving the value
 
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs
new file mode 100644
index 0000000..0b8ec23
--- /dev/null
+++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs
@@ -0,0 +1,148 @@
+use std::assert_matches::assert_matches;
+use std::collections::hash_map::Entry;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
+use rustc_middle::mir::{self, BasicBlock, UnOp};
+use rustc_middle::thir::{ExprId, ExprKind, Thir};
+use rustc_middle::ty::TyCtxt;
+use rustc_span::def_id::LocalDefId;
+
+use crate::build::Builder;
+
+pub(crate) struct BranchInfoBuilder {
+    /// Maps condition expressions to their enclosing `!`, for better instrumentation.
+    nots: FxHashMap<ExprId, NotInfo>,
+
+    num_block_markers: usize,
+    branch_spans: Vec<BranchSpan>,
+}
+
+#[derive(Clone, Copy)]
+struct NotInfo {
+    /// When visiting the associated expression as a branch condition, treat this
+    /// enclosing `!` as the branch condition instead.
+    enclosing_not: ExprId,
+    /// True if the associated expression is nested within an odd number of `!`
+    /// expressions relative to `enclosing_not` (inclusive of `enclosing_not`).
+    is_flipped: bool,
+}
+
+impl BranchInfoBuilder {
+    /// Creates a new branch info builder, but only if branch coverage instrumentation
+    /// is enabled and `def_id` represents a function that is eligible for coverage.
+    pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> {
+        if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) {
+            Some(Self { nots: FxHashMap::default(), num_block_markers: 0, branch_spans: vec![] })
+        } else {
+            None
+        }
+    }
+
+    /// Unary `!` expressions inside an `if` condition are lowered by lowering
+    /// their argument instead, and then reversing the then/else arms of that `if`.
+    ///
+    /// That's awkward for branch coverage instrumentation, so to work around that
+    /// we pre-emptively visit any affected `!` expressions, and record extra
+    /// information that [`Builder::visit_coverage_branch_condition`] can use to
+    /// synthesize branch instrumentation for the enclosing `!`.
+    pub(crate) fn visit_unary_not(&mut self, thir: &Thir<'_>, unary_not: ExprId) {
+        assert_matches!(thir[unary_not].kind, ExprKind::Unary { op: UnOp::Not, .. });
+
+        self.visit_with_not_info(
+            thir,
+            unary_not,
+            // Set `is_flipped: false` for the `!` itself, so that its enclosed
+            // expression will have `is_flipped: true`.
+            NotInfo { enclosing_not: unary_not, is_flipped: false },
+        );
+    }
+
+    fn visit_with_not_info(&mut self, thir: &Thir<'_>, expr_id: ExprId, not_info: NotInfo) {
+        match self.nots.entry(expr_id) {
+            // This expression has already been marked by an enclosing `!`.
+            Entry::Occupied(_) => return,
+            Entry::Vacant(entry) => entry.insert(not_info),
+        };
+
+        match thir[expr_id].kind {
+            ExprKind::Unary { op: UnOp::Not, arg } => {
+                // Invert the `is_flipped` flag for the contents of this `!`.
+                let not_info = NotInfo { is_flipped: !not_info.is_flipped, ..not_info };
+                self.visit_with_not_info(thir, arg, not_info);
+            }
+            ExprKind::Scope { value, .. } => self.visit_with_not_info(thir, value, not_info),
+            ExprKind::Use { source } => self.visit_with_not_info(thir, source, not_info),
+            // All other expressions (including `&&` and `||`) don't need any
+            // special handling of their contents, so stop visiting.
+            _ => {}
+        }
+    }
+
+    fn next_block_marker_id(&mut self) -> BlockMarkerId {
+        let id = BlockMarkerId::from_usize(self.num_block_markers);
+        self.num_block_markers += 1;
+        id
+    }
+
+    pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
+        let Self { nots: _, num_block_markers, branch_spans } = self;
+
+        if num_block_markers == 0 {
+            assert!(branch_spans.is_empty());
+            return None;
+        }
+
+        Some(Box::new(mir::coverage::BranchInfo { num_block_markers, branch_spans }))
+    }
+}
+
+impl Builder<'_, '_> {
+    /// If branch coverage is enabled, inject marker statements into `then_block`
+    /// and `else_block`, and record their IDs in the table of branch spans.
+    pub(crate) fn visit_coverage_branch_condition(
+        &mut self,
+        mut expr_id: ExprId,
+        mut then_block: BasicBlock,
+        mut else_block: BasicBlock,
+    ) {
+        // Bail out if branch coverage is not enabled for this function.
+        let Some(branch_info) = self.coverage_branch_info.as_ref() else { return };
+
+        // If this condition expression is nested within one or more `!` expressions,
+        // replace it with the enclosing `!` collected by `visit_unary_not`.
+        if let Some(&NotInfo { enclosing_not, is_flipped }) = branch_info.nots.get(&expr_id) {
+            expr_id = enclosing_not;
+            if is_flipped {
+                std::mem::swap(&mut then_block, &mut else_block);
+            }
+        }
+        let source_info = self.source_info(self.thir[expr_id].span);
+
+        // Now that we have `source_info`, we can upgrade to a &mut reference.
+        let branch_info = self.coverage_branch_info.as_mut().expect("upgrading & to &mut");
+
+        let mut inject_branch_marker = |block: BasicBlock| {
+            let id = branch_info.next_block_marker_id();
+
+            let marker_statement = mir::Statement {
+                source_info,
+                kind: mir::StatementKind::Coverage(Box::new(mir::Coverage {
+                    kind: CoverageKind::BlockMarker { id },
+                })),
+            };
+            self.cfg.push(block, marker_statement);
+
+            id
+        };
+
+        let true_marker = inject_branch_marker(then_block);
+        let false_marker = inject_branch_marker(else_block);
+
+        branch_info.branch_spans.push(BranchSpan {
+            span: source_info.span,
+            true_marker,
+            false_marker,
+        });
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index c2bff90..288b787 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -60,6 +60,7 @@
         tainted_by_errors: None,
         injection_phase: None,
         pass_count: 0,
+        coverage_branch_info: None,
         function_coverage_info: None,
     };
 
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 4d5ed65..e7808ff 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -105,6 +105,13 @@
                 success_block.unit()
             }
             ExprKind::Unary { op: UnOp::Not, arg } => {
+                // Improve branch coverage instrumentation by noting conditions
+                // nested within one or more `!` expressions.
+                // (Skipped if branch coverage is not enabled.)
+                if let Some(branch_info) = this.coverage_branch_info.as_mut() {
+                    branch_info.visit_unary_not(this.thir, expr_id);
+                }
+
                 let local_scope = this.local_scope();
                 let (success_block, failure_block) =
                     this.in_if_then_scope(local_scope, expr_span, |this| {
@@ -149,6 +156,10 @@
                 let else_block = this.cfg.start_new_block();
                 let term = TerminatorKind::if_(operand, then_block, else_block);
 
+                // Record branch coverage info for this condition.
+                // (Does nothing if branch coverage is not enabled.)
+                this.visit_coverage_branch_condition(expr_id, then_block, else_block);
+
                 let source_info = this.source_info(expr_span);
                 this.cfg.terminate(block, source_info, term);
                 this.break_for_else(else_block, source_info);
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 45954bd..411119b 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1,7 +1,7 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
 use itertools::Itertools;
-use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_apfloat::Float;
 use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
@@ -234,6 +234,10 @@
     // the root (most of them do) and saves us from retracing many sub-paths
     // many times, and rechecking many nodes.
     lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>,
+
+    /// Collects additional coverage information during MIR building.
+    /// Only present if branch coverage is enabled and this function is eligible.
+    coverage_branch_info: Option<coverageinfo::BranchInfoBuilder>,
 }
 
 type CaptureMap<'tcx> = SortedIndexMultiMap<usize, hir::HirId, Capture<'tcx>>;
@@ -807,6 +811,7 @@
             unit_temp: None,
             var_debug_info: vec![],
             lint_level_roots_cache: GrowableBitSet::new_empty(),
+            coverage_branch_info: coverageinfo::BranchInfoBuilder::new_if_enabled(tcx, def),
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@@ -826,7 +831,7 @@
             }
         }
 
-        Body::new(
+        let mut body = Body::new(
             MirSource::item(self.def_id.to_def_id()),
             self.cfg.basic_blocks,
             self.source_scopes,
@@ -837,7 +842,9 @@
             self.fn_span,
             self.coroutine,
             None,
-        )
+        );
+        body.coverage_branch_info = self.coverage_branch_info.and_then(|b| b.into_done());
+        body
     }
 
     fn insert_upvar_arg(&mut self) {
@@ -1053,7 +1060,8 @@
 ) -> Option<Scalar> {
     let num = num.as_str();
     match float_ty {
-        ty::FloatTy::F16 => unimplemented!("f16_f128"),
+        // FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64`
+        ty::FloatTy::F16 => num.parse::<Half>().ok().map(Scalar::from_f16),
         ty::FloatTy::F32 => {
             let Ok(rust_f) = num.parse::<f32>() else { return None };
             let mut f = num
@@ -1100,7 +1108,8 @@
 
             Some(Scalar::from_f64(f))
         }
-        ty::FloatTy::F128 => unimplemented!("f16_f128"),
+        // FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64`
+        ty::FloatTy::F128 => num.parse::<Quad>().ok().map(Scalar::from_f128),
     }
 }
 
@@ -1111,6 +1120,7 @@
 
 mod block;
 mod cfg;
+mod coverageinfo;
 mod custom;
 mod expr;
 mod matches;
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 2b4c654..848da56 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -6,7 +6,7 @@
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
-use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcMatchCheckCtxt};
+use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcPatCtxt};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
@@ -455,7 +455,7 @@
 }
 
 pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
-    pub cx: &'m RustcMatchCheckCtxt<'p, 'tcx>,
+    pub cx: &'m RustcPatCtxt<'p, 'tcx>,
     pub expr_span: Span,
     pub span: Span,
     pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 1e93e12..d4a3479 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -63,7 +63,7 @@
                         // ignore for purposes of the MIR
                         None
                     }
-                    hir::StmtKind::Local(local) => {
+                    hir::StmtKind::Let(local) => {
                         let remainder_scope = region::Scope {
                             id: block_id,
                             data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
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 f395bb4..20d3b3f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,7 +1,7 @@
 use rustc_pattern_analysis::errors::Uncovered;
 use rustc_pattern_analysis::rustc::{
-    Constructor, DeconstructedPat, MatchArm, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
-    UsefulnessReport, WitnessPat,
+    Constructor, DeconstructedPat, MatchArm, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport,
+    WitnessPat,
 };
 
 use crate::errors::*;
@@ -276,7 +276,7 @@
 
     fn lower_pattern(
         &mut self,
-        cx: &MatchCheckCtxt<'p, 'tcx>,
+        cx: &PatCtxt<'p, 'tcx>,
         pat: &'p Pat<'tcx>,
     ) -> Result<&'p DeconstructedPat<'p, 'tcx>, ErrorGuaranteed> {
         if let Err(err) = pat.pat_error_reported() {
@@ -375,7 +375,7 @@
         whole_match_span: Option<Span>,
         scrutinee: Option<&Expr<'tcx>>,
         scrut_span: Span,
-    ) -> MatchCheckCtxt<'p, 'tcx> {
+    ) -> PatCtxt<'p, 'tcx> {
         let refutable = match refutability {
             Irrefutable => false,
             Refutable => true,
@@ -384,7 +384,7 @@
         // require validity.
         let known_valid_scrutinee =
             scrutinee.map(|scrut| self.is_known_valid_scrutinee(scrut)).unwrap_or(true);
-        MatchCheckCtxt {
+        PatCtxt {
             tcx: self.tcx,
             typeck_results: self.typeck_results,
             param_env: self.param_env,
@@ -400,7 +400,7 @@
 
     fn analyze_patterns(
         &mut self,
-        cx: &MatchCheckCtxt<'p, 'tcx>,
+        cx: &PatCtxt<'p, 'tcx>,
         arms: &[MatchArm<'p, 'tcx>],
         scrut_ty: Ty<'tcx>,
     ) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
@@ -584,7 +584,7 @@
         pat: &'p Pat<'tcx>,
         refutability: RefutableFlag,
         scrut: Option<&Expr<'tcx>>,
-    ) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
+    ) -> Result<(PatCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
         let cx = self.new_cx(refutability, None, scrut, pat.span);
         let pat = self.lower_pattern(&cx, pat)?;
         let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
@@ -849,7 +849,7 @@
 
 /// Check that never patterns are only used on inhabited types.
 fn check_never_pattern<'tcx>(
-    cx: &MatchCheckCtxt<'_, 'tcx>,
+    cx: &PatCtxt<'_, 'tcx>,
     pat: &Pat<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
     if let PatKind::Never = pat.kind {
@@ -884,7 +884,7 @@
 
 /// Report unreachable arms, if any.
 fn report_unreachable_pattern<'p, 'tcx>(
-    cx: &MatchCheckCtxt<'p, 'tcx>,
+    cx: &PatCtxt<'p, 'tcx>,
     hir_id: HirId,
     span: Span,
     catchall: Option<Span>,
@@ -898,10 +898,7 @@
 }
 
 /// Report unreachable arms, if any.
-fn report_arm_reachability<'p, 'tcx>(
-    cx: &MatchCheckCtxt<'p, 'tcx>,
-    report: &UsefulnessReport<'p, 'tcx>,
-) {
+fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
     let mut catchall = None;
     for (arm, is_useful) in report.arm_usefulness.iter() {
         if matches!(is_useful, Usefulness::Redundant) {
@@ -926,7 +923,7 @@
 
 /// Report that a match is not exhaustive.
 fn report_non_exhaustive_match<'p, 'tcx>(
-    cx: &MatchCheckCtxt<'p, 'tcx>,
+    cx: &PatCtxt<'p, 'tcx>,
     thir: &Thir<'tcx>,
     scrut_ty: Ty<'tcx>,
     sp: Span,
@@ -1126,7 +1123,7 @@
 }
 
 fn joined_uncovered_patterns<'p, 'tcx>(
-    cx: &MatchCheckCtxt<'p, 'tcx>,
+    cx: &PatCtxt<'p, 'tcx>,
     witnesses: &[WitnessPat<'p, 'tcx>],
 ) -> String {
     const LIMIT: usize = 3;
@@ -1147,7 +1144,7 @@
 }
 
 fn collect_non_exhaustive_tys<'tcx>(
-    cx: &MatchCheckCtxt<'_, 'tcx>,
+    cx: &PatCtxt<'_, 'tcx>,
     pat: &WitnessPat<'_, 'tcx>,
     non_exhaustive_tys: &mut FxIndexSet<Ty<'tcx>>,
 ) {
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 430d957..6f668aa 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -118,7 +118,7 @@
         }
 
         // PART 3
-        // Add retag after assignments where data "enters" this function: the RHS is behind a deref and the LHS is not.
+        // Add retag after assignments.
         for block_data in basic_blocks {
             // We want to insert statements as we iterate. To this end, we
             // iterate backwards using indices.
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 4c5be0a..b2407c5 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -14,7 +14,6 @@
 use crate::MirPass;
 
 use rustc_middle::hir;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{
     self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
@@ -44,7 +43,7 @@
 
         let def_id = mir_source.def_id().expect_local();
 
-        if !is_eligible_for_coverage(tcx, def_id) {
+        if !tcx.is_eligible_for_coverage(def_id) {
             trace!("InstrumentCoverage skipped for {def_id:?} (not eligible)");
             return;
         }
@@ -140,6 +139,10 @@
         .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| {
             let kind = match bcb_mapping_kind {
                 BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
+                BcbMappingKind::Branch { true_bcb, false_bcb } => MappingKind::Branch {
+                    true_term: term_for_bcb(true_bcb),
+                    false_term: term_for_bcb(false_bcb),
+                },
             };
             let code_region = make_code_region(source_map, file_name, span, body_span)?;
             Some(Mapping { kind, code_region })
@@ -349,37 +352,6 @@
     }
 }
 
-fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    // Only instrument functions, methods, and closures (not constants since they are evaluated
-    // at compile time by Miri).
-    // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
-    // expressions get coverage spans, we will probably have to "carve out" space for const
-    // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
-    // be tricky if const expressions have no corresponding statements in the enclosing MIR.
-    // Closures are carved out by their initial `Assign` statement.)
-    if !tcx.def_kind(def_id).is_fn_like() {
-        trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)");
-        return false;
-    }
-
-    // Don't instrument functions with `#[automatically_derived]` on their
-    // enclosing impl block, on the assumption that most users won't care about
-    // coverage for derived impls.
-    if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
-        && tcx.is_automatically_derived(impl_of)
-    {
-        trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
-        return false;
-    }
-
-    if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
-        trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
-        return false;
-    }
-
-    true
-}
-
 /// Function information extracted from HIR by the coverage instrumentor.
 #[derive(Debug)]
 struct ExtractedHirInfo {
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index dfc7c3a..1de7b6f 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,14 +1,49 @@
-use super::*;
-
 use rustc_data_structures::captures::Captures;
-use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::{Body, CoverageIdsInfo};
-use rustc_middle::query::Providers;
-use rustc_middle::ty::{self};
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::coverage::{CounterId, CoverageKind};
+use rustc_middle::mir::{Body, Coverage, CoverageIdsInfo, Statement, StatementKind};
+use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::util::Providers;
+use rustc_span::def_id::LocalDefId;
 
-/// A `query` provider for retrieving coverage information injected into MIR.
+/// Registers query/hook implementations related to coverage.
 pub(crate) fn provide(providers: &mut Providers) {
-    providers.coverage_ids_info = |tcx, def_id| coverage_ids_info(tcx, def_id);
+    providers.hooks.is_eligible_for_coverage =
+        |TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id);
+    providers.queries.coverage_ids_info = coverage_ids_info;
+}
+
+/// Hook implementation for [`TyCtxt::is_eligible_for_coverage`].
+fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    // Only instrument functions, methods, and closures (not constants since they are evaluated
+    // at compile time by Miri).
+    // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
+    // expressions get coverage spans, we will probably have to "carve out" space for const
+    // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
+    // be tricky if const expressions have no corresponding statements in the enclosing MIR.
+    // Closures are carved out by their initial `Assign` statement.)
+    if !tcx.def_kind(def_id).is_fn_like() {
+        trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)");
+        return false;
+    }
+
+    // Don't instrument functions with `#[automatically_derived]` on their
+    // enclosing impl block, on the assumption that most users won't care about
+    // coverage for derived impls.
+    if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
+        && tcx.is_automatically_derived(impl_of)
+    {
+        trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
+        return false;
+    }
+
+    if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+        trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
+        return false;
+    }
+
+    true
 }
 
 /// Query implementation for `coverage_ids_info`.
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 4260a6f..672de1f 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -13,6 +13,8 @@
 pub(super) enum BcbMappingKind {
     /// Associates an ordinary executable code span with its corresponding BCB.
     Code(BasicCoverageBlock),
+    /// Associates a branch span with BCBs for its true and false arms.
+    Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
 }
 
 #[derive(Debug)]
@@ -66,6 +68,12 @@
             // Each span produced by the generator represents an ordinary code region.
             BcbMapping { kind: BcbMappingKind::Code(bcb), span }
         }));
+
+        mappings.extend(from_mir::extract_branch_mappings(
+            mir_body,
+            hir_info.body_span,
+            basic_coverage_blocks,
+        ));
     }
 
     if mappings.is_empty() {
@@ -80,6 +88,10 @@
     for &BcbMapping { kind, span: _ } in &mappings {
         match kind {
             BcbMappingKind::Code(bcb) => insert(bcb),
+            BcbMappingKind::Branch { true_bcb, false_bcb } => {
+                insert(true_bcb);
+                insert(false_bcb);
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 099a354..86097bd 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -1,7 +1,9 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_index::IndexVec;
+use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
 use rustc_middle::mir::{
-    self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
+    self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
     TerminatorKind,
 };
 use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
@@ -9,6 +11,7 @@
 use crate::coverage::graph::{
     BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
 };
+use crate::coverage::spans::{BcbMapping, BcbMappingKind};
 use crate::coverage::ExtractedHirInfo;
 
 /// Traverses the MIR body to produce an initial collection of coverage-relevant
@@ -179,8 +182,6 @@
 /// If the MIR `Statement` has a span contributive to computing coverage spans,
 /// return it; otherwise return `None`.
 fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
-    use mir::coverage::CoverageKind;
-
     match statement.kind {
         // These statements have spans that are often outside the scope of the executed source code
         // for their parent `BasicBlock`.
@@ -226,6 +227,11 @@
         }
 
         StatementKind::Coverage(box mir::Coverage {
+            // Block markers are used for branch coverage, so ignore them here.
+            kind: CoverageKind::BlockMarker {..}
+        }) => None,
+
+        StatementKind::Coverage(box mir::Coverage {
             // These coverage statements should not exist prior to coverage instrumentation.
             kind: CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. }
         }) => bug!("Unexpected coverage statement found during coverage instrumentation: {statement:?}"),
@@ -358,3 +364,51 @@
         Self { span, visible_macro, bcb, is_hole }
     }
 }
+
+pub(super) fn extract_branch_mappings(
+    mir_body: &mir::Body<'_>,
+    body_span: Span,
+    basic_coverage_blocks: &CoverageGraph,
+) -> Vec<BcbMapping> {
+    let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else {
+        return vec![];
+    };
+
+    let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n(
+        None,
+        branch_info.num_block_markers,
+    );
+
+    // Fill out the mapping from block marker IDs to their enclosing blocks.
+    for (bb, data) in mir_body.basic_blocks.iter_enumerated() {
+        for statement in &data.statements {
+            if let StatementKind::Coverage(coverage) = &statement.kind
+                && let CoverageKind::BlockMarker { id } = coverage.kind
+            {
+                block_markers[id] = Some(bb);
+            }
+        }
+    }
+
+    branch_info
+        .branch_spans
+        .iter()
+        .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| {
+            // For now, ignore any branch span that was introduced by
+            // expansion. This makes things like assert macros less noisy.
+            if !raw_span.ctxt().outer_expn_data().is_root() {
+                return None;
+            }
+            let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?;
+
+            let bcb_from_marker = |marker: BlockMarkerId| {
+                Some(basic_coverage_blocks.bcb_from_bb(block_markers[marker]?)?)
+            };
+
+            let true_bcb = bcb_from_marker(true_marker)?;
+            let false_bcb = bcb_from_marker(false_marker)?;
+
+            Some(BcbMapping { kind: BcbMappingKind::Branch { true_bcb, false_bcb }, span })
+        })
+        .collect::<Vec<_>>()
+}
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index c3e932f..f456196 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -393,7 +393,9 @@
                 }
             }
             Operand::Constant(box constant) => {
-                if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) {
+                if let Ok(constant) =
+                    self.ecx.eval_mir_constant(&constant.const_, Some(constant.span), None)
+                {
                     self.assign_constant(state, place, constant, &[]);
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index d9387ec..0970c4d 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -11,7 +11,7 @@
 use crate::errors;
 
 /// Some of the functions declared as "may unwind" by `fn_can_unwind` can't actually unwind. In
-/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to to consider
+/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to consider
 /// it cannot-unwind here. So below we check `fn_can_unwind() && abi_can_unwind()` before concluding
 /// that a function call can unwind.
 fn abi_can_unwind(abi: Abi) -> bool {
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index ad8f21f..6629fac 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -416,7 +416,8 @@
         match rhs {
             // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
             Operand::Constant(constant) => {
-                let constant = self.ecx.eval_mir_constant(&constant.const_, None, None).ok()?;
+                let constant =
+                    self.ecx.eval_mir_constant(&constant.const_, Some(constant.span), None).ok()?;
                 self.process_constant(bb, lhs, constant, state);
             }
             // Transfer the conditions on the copied rhs.
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 0491de7..4551380 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -37,8 +37,9 @@
     LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue,
     SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
 };
-use rustc_middle::query::Providers;
+use rustc_middle::query;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
+use rustc_middle::util::Providers;
 use rustc_span::{source_map::Spanned, sym, DUMMY_SP};
 use rustc_trait_selection::traits;
 
@@ -124,7 +125,7 @@
     ffi_unwind_calls::provide(providers);
     shim::provide(providers);
     cross_crate_inline::provide(providers);
-    *providers = Providers {
+    providers.queries = query::Providers {
         mir_keys,
         mir_const,
         mir_const_qualif,
@@ -139,7 +140,7 @@
         mir_inliner_callees: inline::cycle::mir_inliner_callees,
         promoted_mir,
         deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
-        ..*providers
+        ..providers.queries
     };
 }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 33a446e..cd9eb49 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -818,21 +818,27 @@
         self.super_rvalue(rvalue, location);
     }
 
-    /// This does not walk the constant, as it has been handled entirely here and trying
-    /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
-    /// work, as some constants cannot be represented in the type system.
+    /// This does not walk the MIR of the constant as that is not needed for codegen, all we need is
+    /// to ensure that the constant evaluates successfully and walk the result.
     #[instrument(skip(self), level = "debug")]
     fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) {
         let const_ = self.monomorphize(constant.const_);
         let param_env = ty::ParamEnv::reveal_all();
-        let val = match const_.eval(self.tcx, param_env, None) {
+        // Evaluate the constant. This makes const eval failure a collection-time error (rather than
+        // a codegen-time error). rustc stops after collection if there was an error, so this
+        // ensures codegen never has to worry about failing consts.
+        // (codegen relies on this and ICEs will happen if this is violated.)
+        let val = match const_.eval(self.tcx, param_env, Some(constant.span)) {
             Ok(v) => v,
-            Err(ErrorHandled::Reported(..)) => return,
             Err(ErrorHandled::TooGeneric(..)) => span_bug!(
                 self.body.source_info(location).span,
                 "collection encountered polymorphic constant: {:?}",
                 const_
             ),
+            Err(err @ ErrorHandled::Reported(..)) => {
+                err.emit_note(self.tcx);
+                return;
+            }
         };
         collect_const_value(self.tcx, val, self.output);
         MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location));
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 296eb31..15041b9 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -1112,6 +1112,9 @@
 
     let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_mode);
 
+    // If there was an error during collection (e.g. from one of the constants we evaluated),
+    // then we stop here. This way codegen does not have to worry about failing constants.
+    // (codegen relies on this and ICEs will happen if this is violated.)
     tcx.dcx().abort_if_errors();
 
     let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || {
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 73f5829..fc90776 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -254,7 +254,7 @@
                 let local = this.parse_local(attrs)?;
                 // FIXME - maybe capture semicolon in recovery?
                 Ok((
-                    this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
+                    this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
                     TrailingToken::None,
                 ))
             })?;
@@ -278,7 +278,7 @@
             } else {
                 TrailingToken::None
             };
-            Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), trailing))
+            Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
         })
     }
 
@@ -764,7 +764,7 @@
                 }
             }
             StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
-            StmtKind::Local(local) if let Err(mut e) = self.expect_semi() => {
+            StmtKind::Let(local) if let Err(mut e) = self.expect_semi() => {
                 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
                 match &mut local.kind {
                     LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
@@ -820,7 +820,7 @@
                 }
                 eat_semi = false;
             }
-            StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => {
+            StmtKind::Empty | StmtKind::Item(_) | StmtKind::Let(_) | StmtKind::Semi(_) => {
                 eat_semi = false
             }
         }
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index 6abfa08..b45a8da 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -18,6 +18,7 @@
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
+rustc_privacy = { path = "../rustc_privacy" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 91ab5b3..eb2399f 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2444,7 +2444,7 @@
 
     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
         // When checking statements ignore expressions, they will be checked later.
-        if let hir::StmtKind::Local(l) = stmt.kind {
+        if let hir::StmtKind::Let(l) = stmt.kind {
             self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
         }
         intravisit::walk_stmt(self, stmt)
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 0371bab..350f7e1 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -33,15 +33,13 @@
 // may need to be marked as live.
 fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     matches!(
-        tcx.opt_hir_node_by_def_id(def_id),
-        Some(
-            Node::Item(..)
-                | Node::ImplItem(..)
-                | Node::ForeignItem(..)
-                | Node::TraitItem(..)
-                | Node::Variant(..)
-                | Node::AnonConst(..)
-        )
+        tcx.hir_node_by_def_id(def_id),
+        Node::Item(..)
+            | Node::ImplItem(..)
+            | Node::ForeignItem(..)
+            | Node::TraitItem(..)
+            | Node::Variant(..)
+            | Node::AnonConst(..)
     )
 }
 
@@ -316,33 +314,31 @@
             // tuple struct constructor function
             let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
 
-            if let Some(node) = self.tcx.opt_hir_node_by_def_id(id) {
-                // When using `#[allow]` or `#[expect]` of `dead_code`, we do a QOL improvement
-                // by declaring fn calls, statics, ... within said items as live, as well as
-                // the item itself, although technically this is not the case.
-                //
-                // This means that the lint for said items will never be fired.
-                //
-                // This doesn't make any difference for the item declared with `#[allow]`, as
-                // the lint firing will be a nop, as it will be silenced by the `#[allow]` of
-                // the item.
-                //
-                // However, for `#[expect]`, the presence or absence of the lint is relevant,
-                // so we don't add it to the list of live symbols when it comes from a
-                // `#[expect]`. This means that we will correctly report an item as live or not
-                // for the `#[expect]` case.
-                //
-                // Note that an item can and will be duplicated on the worklist with different
-                // `ComesFromAllowExpect`, particularly if it was added from the
-                // `effective_visibilities` query or from the `#[allow]`/`#[expect]` checks,
-                // this "duplication" is essential as otherwise a function with `#[expect]`
-                // called from a `pub fn` may be falsely reported as not live, falsely
-                // triggering the `unfulfilled_lint_expectations` lint.
-                if comes_from_allow_expect != ComesFromAllowExpect::Yes {
-                    self.live_symbols.insert(id);
-                }
-                self.visit_node(node);
+            // When using `#[allow]` or `#[expect]` of `dead_code`, we do a QOL improvement
+            // by declaring fn calls, statics, ... within said items as live, as well as
+            // the item itself, although technically this is not the case.
+            //
+            // This means that the lint for said items will never be fired.
+            //
+            // This doesn't make any difference for the item declared with `#[allow]`, as
+            // the lint firing will be a nop, as it will be silenced by the `#[allow]` of
+            // the item.
+            //
+            // However, for `#[expect]`, the presence or absence of the lint is relevant,
+            // so we don't add it to the list of live symbols when it comes from a
+            // `#[expect]`. This means that we will correctly report an item as live or not
+            // for the `#[expect]` case.
+            //
+            // Note that an item can and will be duplicated on the worklist with different
+            // `ComesFromAllowExpect`, particularly if it was added from the
+            // `effective_visibilities` query or from the `#[allow]`/`#[expect]` checks,
+            // this "duplication" is essential as otherwise a function with `#[expect]`
+            // called from a `pub fn` may be falsely reported as not live, falsely
+            // triggering the `unfulfilled_lint_expectations` lint.
+            if comes_from_allow_expect != ComesFromAllowExpect::Yes {
+                self.live_symbols.insert(id);
             }
+            self.visit_node(self.tcx.hir_node_by_def_id(id));
         }
     }
 
@@ -739,8 +735,8 @@
             for local_def_id in local_def_ids {
                 // check the function may construct Self
                 let mut may_construct_self = true;
-                if let Some(hir_id) = tcx.opt_local_def_id_to_hir_id(local_def_id)
-                    && let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id)
+                if let Some(fn_sig) =
+                    tcx.hir().fn_sig_by_hir_id(tcx.local_def_id_to_hir_id(local_def_id))
                 {
                     may_construct_self =
                         matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None);
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 0bab130..2af5a54 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -127,7 +127,7 @@
         {
             // non-local main imports are handled below
             if let Some(def_id) = def_id.as_local()
-                && matches!(tcx.opt_hir_node_by_def_id(def_id), Some(Node::ForeignItem(_)))
+                && matches!(tcx.hir_node_by_def_id(def_id), Node::ForeignItem(_))
             {
                 tcx.dcx().emit_err(ExternMain { span: tcx.def_span(def_id) });
                 return None;
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index be6ba58..d742ffc 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -277,7 +277,7 @@
     fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
         record_variants!(
             (self, s, s.kind, Id::Node(s.hir_id), hir, Stmt, StmtKind),
-            [Local, Item, Expr, Semi]
+            [Let, Item, Expr, Semi]
         );
         hir_visit::walk_stmt(self, s)
     }
@@ -539,7 +539,7 @@
     fn visit_stmt(&mut self, s: &'v ast::Stmt) {
         record_variants!(
             (self, s, s.kind, Id::None, ast, Stmt, StmtKind),
-            [Local, Item, Expr, Semi, Empty, MacCall]
+            [Let, Item, Expr, Semi, Empty, MacCall]
         );
         ast_visit::walk_stmt(self, s)
     }
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index e5033e1..f0c3f7a 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -771,7 +771,7 @@
 
     fn propagate_through_stmt(&mut self, stmt: &hir::Stmt<'_>, succ: LiveNode) -> LiveNode {
         match stmt.kind {
-            hir::StmtKind::Local(local) => {
+            hir::StmtKind::Let(local) => {
                 // Note: we mark the variable as defined regardless of whether
                 // there is an initializer. Initially I had thought to only mark
                 // the live variable as defined if it was initialized, and then we
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 27c9c13..bd34b05 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -280,7 +280,7 @@
     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
         match stmt.kind {
             StmtKind::Item(..) => {}
-            StmtKind::Local(..) => {
+            StmtKind::Let(..) => {
                 self.items.push((ItemKind::NonAsm, stmt.span));
             }
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index e86c052..6eb03bc 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -6,6 +6,7 @@
 // reachable as well.
 
 use hir::def_id::LocalDefIdSet;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,7 +16,8 @@
 use rustc_middle::middle::privacy::{self, Level};
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc};
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt};
+use rustc_privacy::DefIdVisitor;
 use rustc_session::config::CrateType;
 use rustc_target::spec::abi::Abi;
 
@@ -65,23 +67,8 @@
             _ => None,
         };
 
-        if let Some(res) = res
-            && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local())
-        {
-            if self.def_id_represents_local_inlined_item(def_id.to_def_id()) {
-                self.worklist.push(def_id);
-            } else {
-                match res {
-                    // Reachable constants and reachable statics can have their contents inlined
-                    // into other crates. Mark them as reachable and recurse into their body.
-                    Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => {
-                        self.worklist.push(def_id);
-                    }
-                    _ => {
-                        self.reachable_symbols.insert(def_id);
-                    }
-                }
-            }
+        if let Some(res) = res {
+            self.propagate_item(res);
         }
 
         intravisit::walk_expr(self, expr)
@@ -116,26 +103,25 @@
             return false;
         };
 
-        match self.tcx.opt_hir_node_by_def_id(def_id) {
-            Some(Node::Item(item)) => match item.kind {
+        match self.tcx.hir_node_by_def_id(def_id) {
+            Node::Item(item) => match item.kind {
                 hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()),
                 _ => false,
             },
-            Some(Node::TraitItem(trait_method)) => match trait_method.kind {
+            Node::TraitItem(trait_method) => match trait_method.kind {
                 hir::TraitItemKind::Const(_, ref default) => default.is_some(),
                 hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
                 hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
                 | hir::TraitItemKind::Type(..) => false,
             },
-            Some(Node::ImplItem(impl_item)) => match impl_item.kind {
+            Node::ImplItem(impl_item) => match impl_item.kind {
                 hir::ImplItemKind::Const(..) => true,
                 hir::ImplItemKind::Fn(..) => {
                     item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id())
                 }
                 hir::ImplItemKind::Type(_) => false,
             },
-            Some(_) => false,
-            None => false, // This will happen for default methods.
+            _ => false,
         }
     }
 
@@ -147,9 +133,7 @@
                 continue;
             }
 
-            if let Some(ref item) = self.tcx.opt_hir_node_by_def_id(search_item) {
-                self.propagate_node(item, search_item);
-            }
+            self.propagate_node(&self.tcx.hir_node_by_def_id(search_item), search_item);
         }
     }
 
@@ -201,17 +185,9 @@
                     hir::ItemKind::Const(_, _, init) => {
                         self.visit_nested_body(init);
                     }
-
-                    // Reachable statics are inlined if read from another constant or static
-                    // in other crates. Additionally anonymous nested statics may be created
-                    // when evaluating a static, so preserve those, too.
-                    hir::ItemKind::Static(_, _, init) => {
-                        // FIXME(oli-obk): remove this body walking and instead walk the evaluated initializer
-                        // to find nested items that end up in the final value instead of also marking symbols
-                        // as reachable that are only needed for evaluation.
-                        self.visit_nested_body(init);
+                    hir::ItemKind::Static(..) => {
                         if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) {
-                            self.propagate_statics_from_alloc(item.owner_id.def_id, alloc);
+                            self.propagate_from_alloc(alloc);
                         }
                     }
 
@@ -270,7 +246,8 @@
             | Node::Ctor(..)
             | Node::Field(_)
             | Node::Ty(_)
-            | Node::Crate(_) => {}
+            | Node::Crate(_)
+            | Node::AssocOpaqueTy(..) => {}
             _ => {
                 bug!(
                     "found unexpected node kind in worklist: {} ({:?})",
@@ -281,28 +258,89 @@
         }
     }
 
-    /// Finds anonymous nested statics created for nested allocations and adds them to `reachable_symbols`.
-    fn propagate_statics_from_alloc(&mut self, root: LocalDefId, alloc: ConstAllocation<'tcx>) {
+    /// Finds things to add to `reachable_symbols` within allocations.
+    /// In contrast to visit_nested_body this ignores things that were only needed to evaluate
+    /// the allocation.
+    fn propagate_from_alloc(&mut self, alloc: ConstAllocation<'tcx>) {
         if !self.any_library {
             return;
         }
         for (_, prov) in alloc.0.provenance().ptrs().iter() {
             match self.tcx.global_alloc(prov.alloc_id()) {
                 GlobalAlloc::Static(def_id) => {
-                    if let Some(def_id) = def_id.as_local()
-                        && self.tcx.local_parent(def_id) == root
-                        // This is the main purpose of this function: add the def_id we find
-                        // to `reachable_symbols`.
-                        && self.reachable_symbols.insert(def_id)
-                        && let Ok(alloc) = self.tcx.eval_static_initializer(def_id)
-                    {
-                        self.propagate_statics_from_alloc(root, alloc);
+                    self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id))
+                }
+                GlobalAlloc::Function(instance) => {
+                    // Manually visit to actually see the instance's `DefId`. Type visitors won't see it
+                    self.propagate_item(Res::Def(
+                        self.tcx.def_kind(instance.def_id()),
+                        instance.def_id(),
+                    ));
+                    self.visit(instance.args);
+                }
+                GlobalAlloc::VTable(ty, trait_ref) => {
+                    self.visit(ty);
+                    // Manually visit to actually see the trait's `DefId`. Type visitors won't see it
+                    if let Some(trait_ref) = trait_ref {
+                        let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
+                        self.visit_def_id(def_id, "", &"");
+                        self.visit(args);
                     }
                 }
-                GlobalAlloc::Function(_) | GlobalAlloc::VTable(_, _) | GlobalAlloc::Memory(_) => {}
+                GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc),
             }
         }
     }
+
+    fn propagate_item(&mut self, res: Res) {
+        let Res::Def(kind, def_id) = res else { return };
+        let Some(def_id) = def_id.as_local() else { return };
+        match kind {
+            DefKind::Static { nested: true, .. } => {
+                // This is the main purpose of this function: add the def_id we find
+                // to `reachable_symbols`.
+                if self.reachable_symbols.insert(def_id) {
+                    if let Ok(alloc) = self.tcx.eval_static_initializer(def_id) {
+                        // This cannot cause infinite recursion, because we abort by inserting into the
+                        // work list once we hit a normal static. Nested statics, even if they somehow
+                        // become recursive, are also not infinitely recursing, because of the
+                        // `reachable_symbols` check above.
+                        // We still need to protect against stack overflow due to deeply nested statics.
+                        ensure_sufficient_stack(|| self.propagate_from_alloc(alloc));
+                    }
+                }
+            }
+            // Reachable constants and reachable statics can have their contents inlined
+            // into other crates. Mark them as reachable and recurse into their body.
+            DefKind::Const | DefKind::AssocConst | DefKind::Static { .. } => {
+                self.worklist.push(def_id);
+            }
+            _ => {
+                if self.def_id_represents_local_inlined_item(def_id.to_def_id()) {
+                    self.worklist.push(def_id);
+                } else {
+                    self.reachable_symbols.insert(def_id);
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> DefIdVisitor<'tcx> for ReachableContext<'tcx> {
+    type Result = ();
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_def_id(
+        &mut self,
+        def_id: DefId,
+        _kind: &str,
+        _descr: &dyn std::fmt::Display,
+    ) -> Self::Result {
+        self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id))
+    }
 }
 
 fn check_item<'tcx>(
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 2d55785..bbb8957 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -40,7 +40,7 @@
 //! - That have no non-trivial intersection with any of the constructors in the column (i.e. they're
 //!     each either disjoint with or covered by any given column constructor).
 //!
-//! We compute this in two steps: first [`TypeCx::ctors_for_ty`] determines the
+//! We compute this in two steps: first [`PatCx::ctors_for_ty`] determines the
 //! set of all possible constructors for the type. Then [`ConstructorSet::split`] looks at the
 //! column of constructors and splits the set into groups accordingly. The precise invariants of
 //! [`ConstructorSet::split`] is described in [`SplitConstructorSet`].
@@ -136,7 +136,7 @@
 //! the algorithm can't distinguish them from a nonempty constructor. The only known case where this
 //! could happen is the `[..]` pattern on `[!; N]` with `N > 0` so we must take care to not emit it.
 //!
-//! This is all handled by [`TypeCx::ctors_for_ty`] and
+//! This is all handled by [`PatCx::ctors_for_ty`] and
 //! [`ConstructorSet::split`]. The invariants of [`SplitConstructorSet`] are also of interest.
 //!
 //!
@@ -162,7 +162,7 @@
 use self::SliceKind::*;
 
 use crate::index;
-use crate::TypeCx;
+use crate::PatCx;
 
 /// Whether we have seen a constructor in the column or not.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -195,8 +195,6 @@
     /// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite_{int,uint}`.
     #[non_exhaustive]
     Finite(u128),
-    /// The integer after `u128::MAX`. We need it to represent `x..=u128::MAX` as an exclusive range.
-    JustAfterMax,
     PosInfinity,
 }
 
@@ -232,18 +230,18 @@
     pub fn minus_one(self) -> Option<Self> {
         match self {
             Finite(n) => n.checked_sub(1).map(Finite),
-            JustAfterMax => Some(Finite(u128::MAX)),
             x => Some(x),
         }
     }
-    /// Note: this will not turn a finite value into an infinite one or vice-versa.
+    /// Note: this will turn `u128::MAX` into `PosInfinity`. This means `plus_one` and `minus_one`
+    /// are not strictly inverses, but that poses no problem in our use of them.
+    /// this will not turn a finite value into an infinite one or vice-versa.
     pub fn plus_one(self) -> Option<Self> {
         match self {
             Finite(n) => match n.checked_add(1) {
                 Some(m) => Some(Finite(m)),
-                None => Some(JustAfterMax),
+                None => Some(PosInfinity),
             },
-            JustAfterMax => None,
             x => Some(x),
         }
     }
@@ -277,8 +275,7 @@
     }
 
     /// Construct a range with these boundaries.
-    /// `lo` must not be `PosInfinity` or `JustAfterMax`. `hi` must not be `NegInfinity`.
-    /// If `end` is `Included`, `hi` must also not be `JustAfterMax`.
+    /// `lo` must not be `PosInfinity`. `hi` must not be `NegInfinity`.
     #[inline]
     pub fn from_range(lo: MaybeInfiniteInt, mut hi: MaybeInfiniteInt, end: RangeEnd) -> IntRange {
         if end == RangeEnd::Included {
@@ -651,7 +648,7 @@
 /// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
 /// `Fields`.
 #[derive(Debug)]
-pub enum Constructor<Cx: TypeCx> {
+pub enum Constructor<Cx: PatCx> {
     /// Tuples and structs.
     Struct,
     /// Enum variants.
@@ -696,7 +693,7 @@
     PrivateUninhabited,
 }
 
-impl<Cx: TypeCx> Clone for Constructor<Cx> {
+impl<Cx: PatCx> Clone for Constructor<Cx> {
     fn clone(&self) -> Self {
         match self {
             Constructor::Struct => Constructor::Struct,
@@ -720,7 +717,7 @@
     }
 }
 
-impl<Cx: TypeCx> Constructor<Cx> {
+impl<Cx: PatCx> Constructor<Cx> {
     pub(crate) fn is_non_exhaustive(&self) -> bool {
         matches!(self, NonExhaustive)
     }
@@ -838,7 +835,7 @@
 /// In terms of division of responsibility, [`ConstructorSet::split`] handles all of the
 /// `exhaustive_patterns` feature.
 #[derive(Debug)]
-pub enum ConstructorSet<Cx: TypeCx> {
+pub enum ConstructorSet<Cx: PatCx> {
     /// The type is a tuple or struct. `empty` tracks whether the type is empty.
     Struct { empty: bool },
     /// This type has the following list of constructors. If `variants` is empty and
@@ -889,13 +886,13 @@
 /// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be
 /// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4.
 #[derive(Debug)]
-pub struct SplitConstructorSet<Cx: TypeCx> {
+pub struct SplitConstructorSet<Cx: PatCx> {
     pub present: SmallVec<[Constructor<Cx>; 1]>,
     pub missing: Vec<Constructor<Cx>>,
     pub missing_empty: Vec<Constructor<Cx>>,
 }
 
-impl<Cx: TypeCx> ConstructorSet<Cx> {
+impl<Cx: PatCx> ConstructorSet<Cx> {
     /// This analyzes a column of constructors to 1/ determine which constructors of the type (if
     /// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
     /// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 21a61d4..75b7b7c 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -4,7 +4,7 @@
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
 
-use crate::rustc::{RustcMatchCheckCtxt, WitnessPat};
+use crate::rustc::{RustcPatCtxt, WitnessPat};
 
 #[derive(Subdiagnostic)]
 #[label(pattern_analysis_uncovered)]
@@ -21,7 +21,7 @@
 impl<'tcx> Uncovered<'tcx> {
     pub fn new<'p>(
         span: Span,
-        cx: &RustcMatchCheckCtxt<'p, 'tcx>,
+        cx: &RustcPatCtxt<'p, 'tcx>,
         witnesses: Vec<WitnessPat<'p, 'tcx>>,
     ) -> Self
     where
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index f632eaf..5c57c99 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -84,7 +84,7 @@
 /// Context that provides type information about constructors.
 ///
 /// Most of the crate is parameterized on a type that implements this trait.
-pub trait TypeCx: Sized + fmt::Debug {
+pub trait PatCx: Sized + fmt::Debug {
     /// The type of a pattern.
     type Ty: Clone + fmt::Debug;
     /// Errors that can abort analysis.
@@ -155,34 +155,34 @@
 
 /// The arm of a match expression.
 #[derive(Debug)]
-pub struct MatchArm<'p, Cx: TypeCx> {
+pub struct MatchArm<'p, Cx: PatCx> {
     pub pat: &'p DeconstructedPat<Cx>,
     pub has_guard: bool,
     pub arm_data: Cx::ArmData,
 }
 
-impl<'p, Cx: TypeCx> Clone for MatchArm<'p, Cx> {
+impl<'p, Cx: PatCx> Clone for MatchArm<'p, Cx> {
     fn clone(&self) -> Self {
         Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data }
     }
 }
 
-impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {}
+impl<'p, Cx: PatCx> Copy for MatchArm<'p, Cx> {}
 
 /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
 /// useful, and runs some lints.
 #[cfg(feature = "rustc")]
 pub fn analyze_match<'p, 'tcx>(
-    tycx: &rustc::RustcMatchCheckCtxt<'p, 'tcx>,
+    tycx: &rustc::RustcPatCtxt<'p, 'tcx>,
     arms: &[rustc::MatchArm<'p, 'tcx>],
     scrut_ty: Ty<'tcx>,
     pattern_complexity_limit: Option<usize>,
 ) -> Result<rustc::UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
     use lints::lint_nonexhaustive_missing_variants;
-    use usefulness::{compute_match_usefulness, ValidityConstraint};
+    use usefulness::{compute_match_usefulness, PlaceValidity};
 
     let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
-    let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
+    let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee);
     let report =
         compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?;
 
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index 072a8e4..3ca5ebd 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -4,15 +4,15 @@
 use crate::constructor::Constructor;
 use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered};
 use crate::pat_column::PatternColumn;
-use crate::rustc::{RevealedTy, RustcMatchCheckCtxt, WitnessPat};
+use crate::rustc::{RevealedTy, RustcPatCtxt, WitnessPat};
 use crate::MatchArm;
 
 /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
 /// in a given column.
 #[instrument(level = "debug", skip(cx), ret)]
 fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
-    cx: &RustcMatchCheckCtxt<'p, 'tcx>,
-    column: &PatternColumn<'p, RustcMatchCheckCtxt<'p, 'tcx>>,
+    cx: &RustcPatCtxt<'p, 'tcx>,
+    column: &PatternColumn<'p, RustcPatCtxt<'p, 'tcx>>,
 ) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> {
     let Some(&ty) = column.head_ty() else {
         return Ok(Vec::new());
@@ -57,9 +57,9 @@
 }
 
 pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
-    rcx: &RustcMatchCheckCtxt<'p, 'tcx>,
-    arms: &[MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>],
-    pat_column: &PatternColumn<'p, RustcMatchCheckCtxt<'p, 'tcx>>,
+    rcx: &RustcPatCtxt<'p, 'tcx>,
+    arms: &[MatchArm<'p, RustcPatCtxt<'p, 'tcx>>],
+    pat_column: &PatternColumn<'p, RustcPatCtxt<'p, 'tcx>>,
     scrut_ty: RevealedTy<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
     if !matches!(
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index cefc1d8..e3667d4 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -5,7 +5,7 @@
 use smallvec::{smallvec, SmallVec};
 
 use crate::constructor::{Constructor, Slice, SliceKind};
-use crate::{PrivateUninhabitedField, TypeCx};
+use crate::{PatCx, PrivateUninhabitedField};
 
 use self::Constructor::*;
 
@@ -21,7 +21,7 @@
 }
 
 /// A pattern with an index denoting which field it corresponds to.
-pub struct IndexedPat<Cx: TypeCx> {
+pub struct IndexedPat<Cx: PatCx> {
     pub idx: usize,
     pub pat: DeconstructedPat<Cx>,
 }
@@ -29,7 +29,7 @@
 /// Values and patterns can be represented as a constructor applied to some fields. This represents
 /// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
 /// exception are some `Wildcard`s introduced during pattern lowering.
-pub struct DeconstructedPat<Cx: TypeCx> {
+pub struct DeconstructedPat<Cx: PatCx> {
     ctor: Constructor<Cx>,
     fields: Vec<IndexedPat<Cx>>,
     /// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
@@ -43,7 +43,7 @@
     pub(crate) uid: PatId,
 }
 
-impl<Cx: TypeCx> DeconstructedPat<Cx> {
+impl<Cx: PatCx> DeconstructedPat<Cx> {
     pub fn new(
         ctor: Constructor<Cx>,
         fields: Vec<IndexedPat<Cx>>,
@@ -136,7 +136,7 @@
 }
 
 /// This is best effort and not good enough for a `Display` impl.
-impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
+impl<Cx: PatCx> fmt::Debug for DeconstructedPat<Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let pat = self;
         let mut first = true;
@@ -219,14 +219,14 @@
 /// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
 ///
 /// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
-pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
+pub(crate) enum PatOrWild<'p, Cx: PatCx> {
     /// A non-user-provided wildcard, created during specialization.
     Wild,
     /// A user-provided pattern.
     Pat(&'p DeconstructedPat<Cx>),
 }
 
-impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
+impl<'p, Cx: PatCx> Clone for PatOrWild<'p, Cx> {
     fn clone(&self) -> Self {
         match self {
             PatOrWild::Wild => PatOrWild::Wild,
@@ -235,9 +235,9 @@
     }
 }
 
-impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {}
+impl<'p, Cx: PatCx> Copy for PatOrWild<'p, Cx> {}
 
-impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
+impl<'p, Cx: PatCx> PatOrWild<'p, Cx> {
     pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
         match self {
             PatOrWild::Wild => None,
@@ -283,7 +283,7 @@
     }
 }
 
-impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> {
+impl<'p, Cx: PatCx> fmt::Debug for PatOrWild<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             PatOrWild::Wild => write!(f, "_"),
@@ -295,19 +295,19 @@
 /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
 /// purposes. As such they don't use interning and can be cloned.
 #[derive(Debug)]
-pub struct WitnessPat<Cx: TypeCx> {
+pub struct WitnessPat<Cx: PatCx> {
     ctor: Constructor<Cx>,
     pub(crate) fields: Vec<WitnessPat<Cx>>,
     ty: Cx::Ty,
 }
 
-impl<Cx: TypeCx> Clone for WitnessPat<Cx> {
+impl<Cx: PatCx> Clone for WitnessPat<Cx> {
     fn clone(&self) -> Self {
         Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
     }
 }
 
-impl<Cx: TypeCx> WitnessPat<Cx> {
+impl<Cx: PatCx> WitnessPat<Cx> {
     pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
         Self { ctor, fields, ty }
     }
diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs
index ce14fdc..eb4e095 100644
--- a/compiler/rustc_pattern_analysis/src/pat_column.rs
+++ b/compiler/rustc_pattern_analysis/src/pat_column.rs
@@ -1,6 +1,6 @@
 use crate::constructor::{Constructor, SplitConstructorSet};
 use crate::pat::{DeconstructedPat, PatOrWild};
-use crate::{Captures, MatchArm, TypeCx};
+use crate::{Captures, MatchArm, PatCx};
 
 /// A column of patterns in a match, where a column is the intuitive notion of "subpatterns that
 /// inspect the same subvalue/place".
@@ -11,12 +11,12 @@
 ///
 /// This is not used in the usefulness algorithm; only in lints.
 #[derive(Debug)]
-pub struct PatternColumn<'p, Cx: TypeCx> {
+pub struct PatternColumn<'p, Cx: PatCx> {
     /// This must not contain an or-pattern. `expand_and_push` takes care to expand them.
     patterns: Vec<&'p DeconstructedPat<Cx>>,
 }
 
-impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
+impl<'p, Cx: PatCx> PatternColumn<'p, Cx> {
     pub fn new(arms: &[MatchArm<'p, Cx>]) -> Self {
         let patterns = Vec::with_capacity(arms.len());
         let mut column = PatternColumn { patterns };
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 53a32d3..fd51fbe 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -18,20 +18,19 @@
 use crate::constructor::{
     IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
 };
-use crate::{errors, Captures, PrivateUninhabitedField, TypeCx};
+use crate::{errors, Captures, PatCx, PrivateUninhabitedField};
 
 use crate::constructor::Constructor::*;
 
 // Re-export rustc-specific versions of all these types.
-pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type ConstructorSet<'p, 'tcx> =
-    crate::constructor::ConstructorSet<RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcPatCtxt<'p, 'tcx>>;
+pub type ConstructorSet<'p, 'tcx> = crate::constructor::ConstructorSet<RustcPatCtxt<'p, 'tcx>>;
+pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcPatCtxt<'p, 'tcx>>;
+pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcPatCtxt<'p, 'tcx>>;
+pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcPatCtxt<'p, 'tcx>>;
 pub type UsefulnessReport<'p, 'tcx> =
-    crate::usefulness::UsefulnessReport<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, 'tcx>>;
+    crate::usefulness::UsefulnessReport<'p, RustcPatCtxt<'p, 'tcx>>;
+pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcPatCtxt<'p, 'tcx>>;
 
 /// A type which has gone through `cx.reveal_opaque_ty`, i.e. if it was opaque it was replaced by
 /// the hidden type if allowed in the current body. This ensures we consistently inspect the hidden
@@ -62,7 +61,7 @@
 }
 
 #[derive(Clone)]
-pub struct RustcMatchCheckCtxt<'p, 'tcx: 'p> {
+pub struct RustcPatCtxt<'p, 'tcx: 'p> {
     pub tcx: TyCtxt<'tcx>,
     pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
     /// The module in which the match occurs. This is necessary for
@@ -87,22 +86,19 @@
     pub known_valid_scrutinee: bool,
 }
 
-impl<'p, 'tcx: 'p> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> fmt::Debug for RustcPatCtxt<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RustcMatchCheckCtxt").finish()
+        f.debug_struct("RustcPatCtxt").finish()
     }
 }
 
-impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     /// Type inference occasionally gives us opaque types in places where corresponding patterns
     /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
     /// types, we use the corresponding concrete type if possible.
     #[inline]
     pub fn reveal_opaque_ty(&self, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
-        fn reveal_inner<'tcx>(
-            cx: &RustcMatchCheckCtxt<'_, 'tcx>,
-            ty: Ty<'tcx>,
-        ) -> RevealedTy<'tcx> {
+        fn reveal_inner<'tcx>(cx: &RustcPatCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> RevealedTy<'tcx> {
             let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!() };
             if let Some(local_def_id) = alias_ty.def_id.as_local() {
                 let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
@@ -199,7 +195,7 @@
     + ExactSizeIterator
     + Captures<'a> {
         fn reveal_and_alloc<'a, 'tcx>(
-            cx: &'a RustcMatchCheckCtxt<'_, 'tcx>,
+            cx: &'a RustcPatCtxt<'_, 'tcx>,
             iter: impl Iterator<Item = Ty<'tcx>>,
         ) -> &'a [(RevealedTy<'tcx>, PrivateUninhabitedField)] {
             cx.dropless_arena.alloc_from_iter(
@@ -218,7 +214,7 @@
                         reveal_and_alloc(cx, once(args.type_at(0)))
                     } else {
                         let variant =
-                            &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
+                            &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
 
                         // In the cases of either a `#[non_exhaustive]` field list or a non-public
                         // field, we skip uninhabited fields in order not to reveal the
@@ -270,7 +266,7 @@
                         // patterns. If we're here we can assume this is a box pattern.
                         1
                     } else {
-                        let variant_idx = RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt);
+                        let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
                         adt.variant(variant_idx).fields.len()
                     }
                 }
@@ -506,7 +502,7 @@
                             _ => bug!(),
                         };
                         let variant =
-                            &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
+                            &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
                         arity = variant.fields.len();
                         fields = subpatterns
                             .iter()
@@ -710,7 +706,7 @@
                     None => PatRangeBoundary::PosInfinity,
                 }
             }
-            JustAfterMax | PosInfinity => PatRangeBoundary::PosInfinity,
+            PosInfinity => PatRangeBoundary::PosInfinity,
         }
     }
 
@@ -774,8 +770,7 @@
                     PatKind::Deref { subpattern: subpatterns.next().unwrap() }
                 }
                 ty::Adt(adt_def, args) => {
-                    let variant_index =
-                        RustcMatchCheckCtxt::variant_index_for_adt(&pat.ctor(), *adt_def);
+                    let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), *adt_def);
                     let subpatterns = subpatterns
                         .enumerate()
                         .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
@@ -843,7 +838,7 @@
     }
 }
 
-impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
     type Ty = RevealedTy<'tcx>;
     type Error = ErrorGuaranteed;
     type VariantIdx = VariantIdx;
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 0834d08..3760db8 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -242,7 +242,7 @@
 //! Therefore `usefulness(tp_1, tp_2, tq)` returns the single witness-tuple `[Variant2(Some(true), 0)]`.
 //!
 //!
-//! Computing the set of constructors for a type is done in [`TypeCx::ctors_for_ty`]. See
+//! Computing the set of constructors for a type is done in [`PatCx::ctors_for_ty`]. See
 //! the following sections for more accurate versions of the algorithm and corresponding links.
 //!
 //!
@@ -540,8 +540,8 @@
 //! We track in the algorithm whether a given place is known to contain valid data. This is done
 //! first by inspecting the scrutinee syntactically (which gives us `cx.known_valid_scrutinee`), and
 //! then by tracking validity of each column of the matrix (which correspond to places) as we
-//! recurse into subpatterns. That second part is done through [`ValidityConstraint`], most notably
-//! [`ValidityConstraint::specialize`].
+//! recurse into subpatterns. That second part is done through [`PlaceValidity`], most notably
+//! [`PlaceValidity::specialize`].
 //!
 //! Having said all that, in practice we don't fully follow what's been presented in this section.
 //! Let's call "toplevel exception" the case where the match scrutinee itself has type `!` or
@@ -716,9 +716,9 @@
 
 use crate::constructor::{Constructor, ConstructorSet, IntRange};
 use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat};
-use crate::{Captures, MatchArm, PrivateUninhabitedField, TypeCx};
+use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField};
 
-use self::ValidityConstraint::*;
+use self::PlaceValidity::*;
 
 #[cfg(feature = "rustc")]
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -728,7 +728,7 @@
 }
 
 /// Context that provides information for usefulness checking.
-struct UsefulnessCtxt<'a, Cx: TypeCx> {
+struct UsefulnessCtxt<'a, Cx: PatCx> {
     /// The context for type information.
     tycx: &'a Cx,
     /// Collect the patterns found useful during usefulness checking. This is used to lint
@@ -738,7 +738,7 @@
     complexity_level: usize,
 }
 
-impl<'a, Cx: TypeCx> UsefulnessCtxt<'a, Cx> {
+impl<'a, Cx: PatCx> UsefulnessCtxt<'a, Cx> {
     fn increase_complexity_level(&mut self, complexity_add: usize) -> Result<(), Cx::Error> {
         self.complexity_level += complexity_add;
         if self
@@ -752,26 +752,26 @@
 }
 
 /// Context that provides information local to a place under investigation.
-struct PlaceCtxt<'a, Cx: TypeCx> {
+struct PlaceCtxt<'a, Cx: PatCx> {
     cx: &'a Cx,
     /// Type of the place under investigation.
     ty: &'a Cx::Ty,
 }
 
-impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {}
-impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> {
+impl<'a, Cx: PatCx> Copy for PlaceCtxt<'a, Cx> {}
+impl<'a, Cx: PatCx> Clone for PlaceCtxt<'a, Cx> {
     fn clone(&self) -> Self {
         Self { cx: self.cx, ty: self.ty }
     }
 }
 
-impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> {
+impl<'a, Cx: PatCx> fmt::Debug for PlaceCtxt<'a, Cx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish()
     }
 }
 
-impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
+impl<'a, Cx: PatCx> PlaceCtxt<'a, Cx> {
     fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
         self.cx.ctor_arity(ctor, self.ty)
     }
@@ -780,18 +780,14 @@
     }
 }
 
-/// Serves two purposes:
-/// - in a wildcard, tracks whether the wildcard matches only valid values (i.e. is a binding `_a`)
-///     or also invalid values (i.e. is a true `_` pattern).
-/// - in the matrix, track whether a given place (aka column) is known to contain a valid value or
-///     not.
+/// Track whether a given place (aka column) is known to contain a valid value or not.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ValidityConstraint {
+pub enum PlaceValidity {
     ValidOnly,
     MaybeInvalid,
 }
 
-impl ValidityConstraint {
+impl PlaceValidity {
     pub fn from_bool(is_valid_only: bool) -> Self {
         if is_valid_only { ValidOnly } else { MaybeInvalid }
     }
@@ -806,7 +802,7 @@
     ///
     /// Pending further opsem decisions, the current behavior is: validity is preserved, except
     /// inside `&` and union fields where validity is reset to `MaybeInvalid`.
-    fn specialize<Cx: TypeCx>(self, ctor: &Constructor<Cx>) -> Self {
+    fn specialize<Cx: PatCx>(self, ctor: &Constructor<Cx>) -> Self {
         // We preserve validity except when we go inside a reference or a union field.
         if matches!(ctor, Constructor::Ref | Constructor::UnionField) {
             // Validity of `x: &T` does not imply validity of `*x: T`.
@@ -817,7 +813,7 @@
     }
 }
 
-impl fmt::Display for ValidityConstraint {
+impl fmt::Display for PlaceValidity {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let s = match self {
             ValidOnly => "✓",
@@ -829,19 +825,19 @@
 
 /// Data about a place under investigation. Its methods contain a lot of the logic used to analyze
 /// the constructors in the matrix.
-struct PlaceInfo<Cx: TypeCx> {
+struct PlaceInfo<Cx: PatCx> {
     /// The type of the place.
     ty: Cx::Ty,
     /// Whether the place is a private uninhabited field. If so we skip this field during analysis
     /// so that we don't observe its emptiness.
     private_uninhabited: bool,
     /// Whether the place is known to contain valid data.
-    validity: ValidityConstraint,
+    validity: PlaceValidity,
     /// Whether the place is the scrutinee itself or a subplace of it.
     is_scrutinee: bool,
 }
 
-impl<Cx: TypeCx> PlaceInfo<Cx> {
+impl<Cx: PatCx> PlaceInfo<Cx> {
     /// Given a constructor for the current place, we return one `PlaceInfo` for each field of the
     /// constructor.
     fn specialize<'a>(
@@ -936,7 +932,7 @@
     }
 }
 
-impl<Cx: TypeCx> Clone for PlaceInfo<Cx> {
+impl<Cx: PatCx> Clone for PlaceInfo<Cx> {
     fn clone(&self) -> Self {
         Self {
             ty: self.ty.clone(),
@@ -951,7 +947,7 @@
 // The three lifetimes are:
 // - 'p coming from the input
 // - Cx global compilation context
-struct PatStack<'p, Cx: TypeCx> {
+struct PatStack<'p, Cx: PatCx> {
     // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
     pats: SmallVec<[PatOrWild<'p, Cx>; 2]>,
     /// Sometimes we know that as far as this row is concerned, the current case is already handled
@@ -960,13 +956,13 @@
     relevant: bool,
 }
 
-impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> {
+impl<'p, Cx: PatCx> Clone for PatStack<'p, Cx> {
     fn clone(&self) -> Self {
         Self { pats: self.pats.clone(), relevant: self.relevant }
     }
 }
 
-impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
+impl<'p, Cx: PatCx> PatStack<'p, Cx> {
     fn from_pattern(pat: &'p DeconstructedPat<Cx>) -> Self {
         PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
     }
@@ -1026,7 +1022,7 @@
     }
 }
 
-impl<'p, Cx: TypeCx> fmt::Debug for PatStack<'p, Cx> {
+impl<'p, Cx: PatCx> fmt::Debug for PatStack<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // We pretty-print similarly to the `Debug` impl of `Matrix`.
         write!(f, "+")?;
@@ -1039,7 +1035,7 @@
 
 /// A row of the matrix.
 #[derive(Clone)]
-struct MatrixRow<'p, Cx: TypeCx> {
+struct MatrixRow<'p, Cx: PatCx> {
     // The patterns in the row.
     pats: PatStack<'p, Cx>,
     /// Whether the original arm had a guard. This is inherited when specializing.
@@ -1059,7 +1055,7 @@
     intersects: BitSet<usize>,
 }
 
-impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
+impl<'p, Cx: PatCx> MatrixRow<'p, Cx> {
     fn is_empty(&self) -> bool {
         self.pats.is_empty()
     }
@@ -1108,7 +1104,7 @@
     }
 }
 
-impl<'p, Cx: TypeCx> fmt::Debug for MatrixRow<'p, Cx> {
+impl<'p, Cx: PatCx> fmt::Debug for MatrixRow<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.pats.fmt(f)
     }
@@ -1125,7 +1121,7 @@
 /// specializing `(,)` and `Some` on a pattern of type `(Option<u32>, bool)`, the first column of
 /// the matrix will correspond to `scrutinee.0.Some.0` and the second column to `scrutinee.1`.
 #[derive(Clone)]
-struct Matrix<'p, Cx: TypeCx> {
+struct Matrix<'p, Cx: PatCx> {
     /// Vector of rows. The rows must form a rectangular 2D array. Moreover, all the patterns of
     /// each column must have the same type. Each column corresponds to a place within the
     /// scrutinee.
@@ -1138,7 +1134,7 @@
     wildcard_row_is_relevant: bool,
 }
 
-impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
+impl<'p, Cx: PatCx> Matrix<'p, Cx> {
     /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
     /// expands it. Internal method, prefer [`Matrix::new`].
     fn expand_and_push(&mut self, mut row: MatrixRow<'p, Cx>) {
@@ -1155,11 +1151,7 @@
     }
 
     /// Build a new matrix from an iterator of `MatchArm`s.
-    fn new(
-        arms: &[MatchArm<'p, Cx>],
-        scrut_ty: Cx::Ty,
-        scrut_validity: ValidityConstraint,
-    ) -> Self {
+    fn new(arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: PlaceValidity) -> Self {
         let place_info = PlaceInfo {
             ty: scrut_ty,
             private_uninhabited: false,
@@ -1264,7 +1256,7 @@
 /// + _     + [_, _, tail @ ..] +
 /// | ✓     | ?                 | // column validity
 /// ```
-impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
+impl<'p, Cx: PatCx> fmt::Debug for Matrix<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "\n")?;
 
@@ -1355,15 +1347,15 @@
 ///
 /// See the top of the file for more detailed explanations and examples.
 #[derive(Debug)]
-struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>);
+struct WitnessStack<Cx: PatCx>(Vec<WitnessPat<Cx>>);
 
-impl<Cx: TypeCx> Clone for WitnessStack<Cx> {
+impl<Cx: PatCx> Clone for WitnessStack<Cx> {
     fn clone(&self) -> Self {
         Self(self.0.clone())
     }
 }
 
-impl<Cx: TypeCx> WitnessStack<Cx> {
+impl<Cx: PatCx> WitnessStack<Cx> {
     /// Asserts that the witness contains a single pattern, and returns it.
     fn single_pattern(self) -> WitnessPat<Cx> {
         assert_eq!(self.0.len(), 1);
@@ -1408,15 +1400,15 @@
 /// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single
 /// column, which contains the patterns that are missing for the match to be exhaustive.
 #[derive(Debug)]
-struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>);
+struct WitnessMatrix<Cx: PatCx>(Vec<WitnessStack<Cx>>);
 
-impl<Cx: TypeCx> Clone for WitnessMatrix<Cx> {
+impl<Cx: PatCx> Clone for WitnessMatrix<Cx> {
     fn clone(&self) -> Self {
         Self(self.0.clone())
     }
 }
 
-impl<Cx: TypeCx> WitnessMatrix<Cx> {
+impl<Cx: PatCx> WitnessMatrix<Cx> {
     /// New matrix with no witnesses.
     fn empty() -> Self {
         WitnessMatrix(Vec::new())
@@ -1490,7 +1482,7 @@
 ///
 /// We can however get false negatives because exhaustiveness does not explore all cases. See the
 /// section on relevancy at the top of the file.
-fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
+fn collect_overlapping_range_endpoints<'p, Cx: PatCx>(
     cx: &Cx,
     overlap_range: IntRange,
     matrix: &Matrix<'p, Cx>,
@@ -1549,7 +1541,7 @@
 }
 
 /// Collect ranges that have a singleton gap between them.
-fn collect_non_contiguous_range_endpoints<'p, Cx: TypeCx>(
+fn collect_non_contiguous_range_endpoints<'p, Cx: PatCx>(
     cx: &Cx,
     gap_range: &IntRange,
     matrix: &Matrix<'p, Cx>,
@@ -1590,7 +1582,7 @@
 ///     (using `apply_constructor` and by updating `row.useful` for each parent row).
 /// This is all explained at the top of the file.
 #[instrument(level = "debug", skip(mcx), ret)]
-fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
+fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>(
     mcx: &mut UsefulnessCtxt<'a, Cx>,
     matrix: &mut Matrix<'p, Cx>,
 ) -> Result<WitnessMatrix<Cx>, Cx::Error> {
@@ -1687,7 +1679,7 @@
 
 /// Indicates whether or not a given arm is useful.
 #[derive(Clone, Debug)]
-pub enum Usefulness<'p, Cx: TypeCx> {
+pub enum Usefulness<'p, Cx: PatCx> {
     /// The arm is useful. This additionally carries a set of or-pattern branches that have been
     /// found to be redundant despite the overall arm being useful. Used only in the presence of
     /// or-patterns, otherwise it stays empty.
@@ -1698,11 +1690,11 @@
 }
 
 /// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
-fn collect_pattern_usefulness<'p, Cx: TypeCx>(
+fn collect_pattern_usefulness<'p, Cx: PatCx>(
     useful_subpatterns: &FxHashSet<PatId>,
     pat: &'p DeconstructedPat<Cx>,
 ) -> Usefulness<'p, Cx> {
-    fn pat_is_useful<'p, Cx: TypeCx>(
+    fn pat_is_useful<'p, Cx: PatCx>(
         useful_subpatterns: &FxHashSet<PatId>,
         pat: &'p DeconstructedPat<Cx>,
     ) -> bool {
@@ -1740,7 +1732,7 @@
 }
 
 /// The output of checking a match for exhaustiveness and arm usefulness.
-pub struct UsefulnessReport<'p, Cx: TypeCx> {
+pub struct UsefulnessReport<'p, Cx: PatCx> {
     /// For each arm of the input, whether that arm is useful after the arms above it.
     pub arm_usefulness: Vec<(MatchArm<'p, Cx>, Usefulness<'p, Cx>)>,
     /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
@@ -1750,11 +1742,11 @@
 
 /// Computes whether a match is exhaustive and which of its arms are useful.
 #[instrument(skip(tycx, arms), level = "debug")]
-pub fn compute_match_usefulness<'p, Cx: TypeCx>(
+pub fn compute_match_usefulness<'p, Cx: PatCx>(
     tycx: &Cx,
     arms: &[MatchArm<'p, Cx>],
     scrut_ty: Cx::Ty,
-    scrut_validity: ValidityConstraint,
+    scrut_validity: PlaceValidity,
     complexity_limit: Option<usize>,
 ) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
     let mut cx = UsefulnessCtxt {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9f8cb8f..073982c 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -67,7 +67,7 @@
 /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
 /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
 /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
-trait DefIdVisitor<'tcx> {
+pub trait DefIdVisitor<'tcx> {
     type Result: VisitorResult = ();
     const SHALLOW: bool = false;
     const SKIP_ASSOC_TYS: bool = false;
@@ -98,7 +98,7 @@
     }
 }
 
-struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
+pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
     def_id_visitor: &'v mut V,
     visited_opaque_tys: FxHashSet<DefId>,
     dummy: PhantomData<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index bf1ea2e..f6004fe 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -23,18 +23,19 @@
 //  - `check_unused` finally emits the diagnostics based on the data generated
 //    in the last step
 
-use crate::imports::ImportKind;
+use crate::imports::{Import, ImportKind};
 use crate::module_to_string;
 use crate::Resolver;
 
-use crate::NameBindingKind;
+use crate::{LexicalScopeBinding, NameBindingKind};
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
 use rustc_hir::def::{DefKind, Res};
-use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES};
+use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, DUMMY_SP};
@@ -514,8 +515,59 @@
             }
         }
 
+        let mut redundant_imports = UnordSet::default();
         for import in check_redundant_imports {
-            self.check_for_redundant_imports(import);
+            if self.check_for_redundant_imports(import)
+                && let Some(id) = import.id()
+            {
+                redundant_imports.insert(id);
+            }
+        }
+
+        // The lint fixes for unused_import and unnecessary_qualification may conflict.
+        // Deleting both unused imports and unnecessary segments of an item may result
+        // in the item not being found.
+        for unn_qua in &self.potentially_unnecessary_qualifications {
+            if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding
+                && let NameBindingKind::Import { import, .. } = name_binding.kind
+                && (is_unused_import(import, &unused_imports)
+                    || is_redundant_import(import, &redundant_imports))
+            {
+                continue;
+            }
+
+            self.lint_buffer.buffer_lint_with_diagnostic(
+                UNUSED_QUALIFICATIONS,
+                unn_qua.node_id,
+                unn_qua.path_span,
+                "unnecessary qualification",
+                BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span },
+            );
+        }
+
+        fn is_redundant_import(
+            import: Import<'_>,
+            redundant_imports: &UnordSet<ast::NodeId>,
+        ) -> bool {
+            if let Some(id) = import.id()
+                && redundant_imports.contains(&id)
+            {
+                return true;
+            }
+            false
+        }
+
+        fn is_unused_import(
+            import: Import<'_>,
+            unused_imports: &FxIndexMap<ast::NodeId, UnusedImport>,
+        ) -> bool {
+            if let Some(unused_import) = unused_imports.get(&import.root_id)
+                && let Some(id) = import.id()
+                && unused_import.unused.contains(&id)
+            {
+                return true;
+            }
+            false
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 6518d97..b24ed57 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -5,8 +5,10 @@
 use rustc_middle::ty;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::lint::BuiltinLintDiag;
+use rustc_session::parse::feature_err;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
+use rustc_span::sym;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
@@ -598,7 +600,35 @@
                         result
                     }
                     Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
-                        Some(binding) => Ok((*binding, Flags::empty())),
+                        Some(binding) => {
+                            if matches!(ident.name, sym::f16)
+                                && !this.tcx.features().f16
+                                && !ident.span.allows_unstable(sym::f16)
+                                && finalize.is_some()
+                            {
+                                feature_err(
+                                    this.tcx.sess,
+                                    sym::f16,
+                                    ident.span,
+                                    "the type `f16` is unstable",
+                                )
+                                .emit();
+                            }
+                            if matches!(ident.name, sym::f128)
+                                && !this.tcx.features().f128
+                                && !ident.span.allows_unstable(sym::f128)
+                                && finalize.is_some()
+                            {
+                                feature_err(
+                                    this.tcx.sess,
+                                    sym::f128,
+                                    ident.span,
+                                    "the type `f128` is unstable",
+                                )
+                                .emit();
+                            }
+                            Ok((*binding, Flags::empty()))
+                        }
                         None => Err(Determinacy::Determined),
                     },
                 };
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index ea08041..9bf3e9c 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1306,7 +1306,7 @@
         None
     }
 
-    pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) {
+    pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) -> bool {
         // This function is only called for single imports.
         let ImportKind::Single {
             source, target, ref source_bindings, ref target_bindings, id, ..
@@ -1317,12 +1317,12 @@
 
         // Skip if the import is of the form `use source as target` and source != target.
         if source != target {
-            return;
+            return false;
         }
 
         // Skip if the import was produced by a macro.
         if import.parent_scope.expansion != LocalExpnId::ROOT {
-            return;
+            return false;
         }
 
         // Skip if we are inside a named module (in contrast to an anonymous
@@ -1332,7 +1332,7 @@
         if import.used.get() == Some(Used::Other)
             || self.effective_visibilities.is_exported(self.local_def_id(id))
         {
-            return;
+            return false;
         }
 
         let mut is_redundant = true;
@@ -1375,7 +1375,10 @@
                 format!("the item `{source}` is imported redundantly"),
                 BuiltinLintDiag::RedundantImport(redundant_spans, source),
             );
+            return true;
         }
+
+        false
     }
 
     fn resolve_glob_import(&mut self, import: Import<'a>) {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index a996188..837c069 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -27,6 +27,7 @@
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
 use rustc_session::lint;
+use rustc_session::parse::feature_err;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
@@ -580,6 +581,15 @@
     }
 }
 
+/// Used for recording UnnecessaryQualification.
+#[derive(Debug)]
+pub(crate) struct UnnecessaryQualification<'a> {
+    pub binding: LexicalScopeBinding<'a>,
+    pub node_id: NodeId,
+    pub path_span: Span,
+    pub removal_span: Span,
+}
+
 #[derive(Default)]
 struct DiagMetadata<'ast> {
     /// The current trait's associated items' ident, used for diagnostic suggestions.
@@ -4129,6 +4139,25 @@
                     && PrimTy::from_name(path[0].ident.name).is_some() =>
             {
                 let prim = PrimTy::from_name(path[0].ident.name).unwrap();
+                let tcx = self.r.tcx();
+
+                let gate_err_sym_msg = match prim {
+                    PrimTy::Float(FloatTy::F16) if !tcx.features().f16 => {
+                        Some((sym::f16, "the type `f16` is unstable"))
+                    }
+                    PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => {
+                        Some((sym::f128, "the type `f128` is unstable"))
+                    }
+                    _ => None,
+                };
+
+                if let Some((sym, msg)) = gate_err_sym_msg {
+                    let span = path[0].ident.span;
+                    if !span.allows_unstable(sym) {
+                        feature_err(tcx.sess, sym, span, msg).emit();
+                    }
+                };
+
                 PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
             }
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
@@ -4654,20 +4683,16 @@
             let ns = if i + 1 == path.len() { ns } else { TypeNS };
             let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?;
             let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?;
-
-            (res == binding.res()).then_some(seg)
+            (res == binding.res()).then_some((seg, binding))
         });
 
-        if let Some(unqualified) = unqualified {
-            self.r.lint_buffer.buffer_lint_with_diagnostic(
-                lint::builtin::UNUSED_QUALIFICATIONS,
-                finalize.node_id,
-                finalize.path_span,
-                "unnecessary qualification",
-                lint::BuiltinLintDiag::UnusedQualifications {
-                    removal_span: path[0].ident.span.until(unqualified.ident.span),
-                },
-            );
+        if let Some((seg, binding)) = unqualified {
+            self.r.potentially_unnecessary_qualifications.push(UnnecessaryQualification {
+                binding,
+                node_id: finalize.node_id,
+                path_span: finalize.path_span,
+                removal_span: path[0].ident.span.until(seg.ident.span),
+            });
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index ccb67ea..dfc2d02 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -68,7 +68,7 @@
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use imports::{Import, ImportData, ImportKind, NameResolution};
-use late::{HasGenericParams, PathSource, PatternSource};
+use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
 use crate::effective_visibilities::EffectiveVisibilitiesVisitor;
@@ -372,7 +372,7 @@
 /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
 /// items are visible in their whole block, while `Res`es only from the place they are defined
 /// forward.
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 enum LexicalScopeBinding<'a> {
     Item(NameBinding<'a>),
     Res(Res),
@@ -1105,6 +1105,8 @@
 
     potentially_unused_imports: Vec<Import<'a>>,
 
+    potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'a>>,
+
     /// Table for mapping struct IDs into struct constructor IDs,
     /// it's not used during normal resolution, only for better error reporting.
     /// Also includes of list of each fields visibility
@@ -1464,6 +1466,7 @@
             local_macro_def_scopes: FxHashMap::default(),
             name_already_seen: FxHashMap::default(),
             potentially_unused_imports: Vec::new(),
+            potentially_unnecessary_qualifications: Default::default(),
             struct_constructors: Default::default(),
             unused_macros: Default::default(),
             unused_macro_rules: Default::default(),
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 4ff4ccf..0ebcad3 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -167,12 +167,13 @@
 ///
 /// Note: remove the trailing newline where appropriate
 pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
-    let s = frag.doc.as_str();
-    let mut iter = s.lines();
-    if s.is_empty() {
+    if frag.doc == kw::Empty {
         out.push('\n');
         return;
     }
+    let s = frag.doc.as_str();
+    let mut iter = s.lines();
+
     while let Some(line) = iter.next() {
         if line.chars().any(|c| !c.is_whitespace()) {
             assert!(line.len() >= frag.indent);
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index af8c962..42c681e 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -111,4 +111,7 @@
 
 session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
 
+session_unsupported_crate_type_for_target =
+    dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
+
 session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 5c52ee6..b7ee2c9 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -146,7 +146,7 @@
 /// Individual flag values controlled by `-Z coverage-options`.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct CoverageOptions {
-    /// Add branch coverage instrumentation (placeholder flag; not yet implemented).
+    /// Add branch coverage instrumentation.
     pub branch: bool,
 }
 
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 5f04915..d523da1 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -10,7 +10,7 @@
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
-use crate::parse::ParseSess;
+use crate::{config::CrateType, parse::ParseSess};
 
 pub struct FeatureGateError {
     pub span: MultiSpan,
@@ -345,6 +345,13 @@
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_unsupported_crate_type_for_target)]
+pub struct UnsupportedCrateTypeForTarget<'a> {
+    pub crate_type: CrateType,
+    pub target_triple: &'a TargetTriple,
+}
+
 pub fn report_lit_error(
     psess: &ParseSess,
     err: LitError,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 2f018fb..b0bd5e7 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1645,6 +1645,8 @@
         "emit the bc module with thin LTO info (default: yes)"),
     export_executable_symbols: bool = (false, parse_bool, [TRACKED],
         "export symbols from executables, as if they were dynamic libraries"),
+    external_clangrt: bool = (false, parse_bool, [UNTRACKED],
+        "rely on user specified linker commands to find clangrt"),
     extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
         "turns on more checks to detect const UB, which can be slow (default: no)"),
     #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")]
@@ -1831,7 +1833,9 @@
     print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
         "print the LLVM optimization passes being run (default: no)"),
     print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "print the result of the monomorphization collection pass"),
+        "print the result of the monomorphization collection pass. \
+         Value `lazy` means to use normal collection; `eager` means to collect all items.
+         Note that this overwrites the effect `-Clink-dead-code` has on collection!"),
     print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
         "print layout information for each type encountered (default: no)"),
     print_vtable_sizes: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index 74d2623..35cd3cb 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -1,7 +1,7 @@
 //! Related to out filenames of compilation (e.g. binaries).
-use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
+use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use crate::errors::{
-    CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
+    self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
     InvalidCharacterInCrateName, InvalidCrateNameHelp,
 };
 use crate::Session;
@@ -200,3 +200,64 @@
 
     false
 }
+
+pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[
+    (sym::rlib, CrateType::Rlib),
+    (sym::dylib, CrateType::Dylib),
+    (sym::cdylib, CrateType::Cdylib),
+    (sym::lib, config::default_lib_output()),
+    (sym::staticlib, CrateType::Staticlib),
+    (sym::proc_dash_macro, CrateType::ProcMacro),
+    (sym::bin, CrateType::Executable),
+];
+
+pub fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
+    Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1)
+}
+
+pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<CrateType> {
+    // If we're generating a test executable, then ignore all other output
+    // styles at all other locations
+    if session.opts.test {
+        return vec![CrateType::Executable];
+    }
+
+    // Only check command line flags if present. If no types are specified by
+    // command line, then reuse the empty `base` Vec to hold the types that
+    // will be found in crate attributes.
+    // JUSTIFICATION: before wrapper fn is available
+    #[allow(rustc::bad_opt_access)]
+    let mut base = session.opts.crate_types.clone();
+    if base.is_empty() {
+        let attr_types = attrs.iter().filter_map(|a| {
+            if a.has_name(sym::crate_type)
+                && let Some(s) = a.value_str()
+            {
+                categorize_crate_type(s)
+            } else {
+                None
+            }
+        });
+        base.extend(attr_types);
+        if base.is_empty() {
+            base.push(default_output_for_target(session));
+        } else {
+            base.sort();
+            base.dedup();
+        }
+    }
+
+    base.retain(|crate_type| {
+        if invalid_output_for_target(session, *crate_type) {
+            session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
+                crate_type: *crate_type,
+                target_triple: &session.opts.target_triple,
+            });
+            false
+        } else {
+            true
+        }
+    });
+
+    base
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs
index 039bdec..a13262c 100644
--- a/compiler/rustc_smir/src/rustc_smir/builder.rs
+++ b/compiler/rustc_smir/src/rustc_smir/builder.rs
@@ -56,7 +56,7 @@
 
     fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) {
         let const_ = self.monomorphize(constant.const_);
-        let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), None) {
+        let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) {
             Ok(v) => v,
             Err(mir::interpret::ErrorHandled::Reported(..)) => return,
             Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 8488777..509f0de 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -23,7 +23,8 @@
 use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
-    ForeignItemKind, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
+    ForeignItemKind, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, UintTy,
+    VariantDef,
 };
 use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
 use std::cell::RefCell;
@@ -341,15 +342,56 @@
             .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
     }
 
-    fn usize_to_const(&self, val: u64) -> Result<Const, Error> {
+    fn try_new_const_zst(&self, ty: Ty) -> Result<Const, Error> {
         let mut tables = self.0.borrow_mut();
-        let ty = tables.tcx.types.usize;
+        let tcx = tables.tcx;
+        let ty_internal = ty.internal(&mut *tables, tcx);
+        let size = tables
+            .tcx
+            .layout_of(ParamEnv::empty().and(ty_internal))
+            .map_err(|err| {
+                Error::new(format!(
+                    "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
+                ))
+            })?
+            .size;
+        if size.bytes() != 0 {
+            return Err(Error::new(format!(
+                "Cannot create a zero-sized constant for type `{ty_internal}`: \
+                 Type `{ty_internal}` has {} bytes",
+                size.bytes()
+            )));
+        }
+
+        Ok(ty::Const::zero_sized(tables.tcx, ty_internal).stable(&mut *tables))
+    }
+
+    fn new_const_str(&self, value: &str) -> Const {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        let ty = ty::Ty::new_static_str(tcx);
+        let bytes = value.as_bytes();
+        let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes);
+
+        ty::Const::new_value(tcx, val_tree, ty).stable(&mut *tables)
+    }
+
+    fn new_const_bool(&self, value: bool) -> Const {
+        let mut tables = self.0.borrow_mut();
+        ty::Const::from_bool(tables.tcx, value).stable(&mut *tables)
+    }
+
+    fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<Const, Error> {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
         let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
 
-        let scalar = ScalarInt::try_from_uint(val, size).ok_or_else(|| {
-            Error::new(format!("Value overflow: cannot convert `{val}` to usize."))
+        // We don't use Const::from_bits since it doesn't have any error checking.
+        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
+            Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`."))
         })?;
-        Ok(rustc_middle::ty::Const::new_value(tables.tcx, ValTree::from_scalar_int(scalar), ty)
+        Ok(ty::Const::new_value(tables.tcx, ValTree::from_scalar_int(scalar), ty)
             .stable(&mut *tables))
     }
 
@@ -556,7 +598,9 @@
         global_alloc: &GlobalAlloc,
     ) -> Option<stable_mir::mir::alloc::AllocId> {
         let mut tables = self.0.borrow_mut();
-        let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else { return None };
+        let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else {
+            return None;
+        };
         let tcx = tables.tcx;
         let alloc_id = tables.tcx.vtable_allocation((
             ty.internal(&mut *tables, tcx),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7de0555..e43c953 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -815,6 +815,9 @@
         fadd_algebraic,
         fadd_fast,
         fake_variadic,
+        fallback_to_never,
+        fallback_to_niko,
+        fallback_to_unit,
         fdiv_algebraic,
         fdiv_fast,
         feature,
@@ -1233,6 +1236,7 @@
         no_crate_inject,
         no_debug,
         no_default_passes,
+        no_fallback,
         no_implicit_prelude,
         no_inline,
         no_link,
@@ -1551,6 +1555,7 @@
         rustc_mir,
         rustc_must_implement_one_of,
         rustc_never_returns_null_ptr,
+        rustc_never_type_mode,
         rustc_no_mir_inline,
         rustc_nonnull_optimization_guaranteed,
         rustc_nounwind,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index cb587e2..486afc5 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -633,10 +633,8 @@
     /// If the resulting alignment differs from the type's alignment,
     /// the argument will be copied to an alloca with sufficient alignment,
     /// either in the caller (if the type's alignment is lower than the byval alignment)
-    /// or in the callee† (if the type's alignment is higher than the byval alignment),
+    /// or in the callee (if the type's alignment is higher than the byval alignment),
     /// to ensure that Rust code never sees an underaligned pointer.
-    ///
-    /// † This is currently broken, see <https://github.com/rust-lang/rust/pull/122212>.
     pub fn make_indirect_byval(&mut self, byval_align: Option<Align>) {
         assert!(!self.layout.is_unsized(), "used byval ABI for unsized layout");
         self.make_indirect();
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index c264a1f..941d767 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -211,7 +211,7 @@
 
 impl LinkerFlavor {
     /// At this point the target's reference linker flavor doesn't yet exist and we need to infer
-    /// it. The inference always succeds and gives some result, and we don't report any flavor
+    /// it. The inference always succeeds and gives some result, and we don't report any flavor
     /// incompatibility errors for json target specs. The CLI flavor is used as the main source
     /// of truth, other flags are used in case of ambiguities.
     fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
@@ -581,7 +581,7 @@
         self == LinkSelfContainedDefault::False
     }
 
-    /// Returns whether the target spec explictly requests self-contained linking, i.e. not via
+    /// Returns whether the target spec explicitly requests self-contained linking, i.e. not via
     /// inference.
     pub fn is_linker_enabled(self) -> bool {
         match self {
@@ -2090,7 +2090,7 @@
     /// If `None`, then `CFG_DEFAULT_CODEGEN_BACKEND` environmental variable captured when
     /// compiling `rustc` will be used instead (or llvm if it is not set).
     ///
-    /// N.B. when *using* the compiler, backend can always be overriden with `-Zcodegen-backend`.
+    /// N.B. when *using* the compiler, backend can always be overridden with `-Zcodegen-backend`.
     pub default_codegen_backend: Option<StaticCow<str>>,
 
     /// Whether to generate trap instructions in places where optimization would
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index af533d8..2bfb86b 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -120,6 +120,8 @@
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     match *ty.kind() {
+        // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, !
+        // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure
         ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Uint(_)
         | ty::Int(_)
@@ -152,8 +154,10 @@
             bug!("unexpected type `{ty}`")
         }
 
+        // impl Sized for (T1, T2, .., Tn) where T1: Sized, T2: Sized, .. Tn: Sized
         ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
 
+        // impl Sized for Adt where T: Sized forall T in field types
         ty::Adt(def, args) => {
             let sized_crit = def.sized_constraint(ecx.tcx());
             Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect())
@@ -167,6 +171,7 @@
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     match *ty.kind() {
+        // impl Copy/Clone for FnDef, FnPtr
         ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
 
         // Implementations are provided in core
@@ -196,12 +201,16 @@
             bug!("unexpected type `{ty}`")
         }
 
+        // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
         ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
 
+        // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
         ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
 
         ty::CoroutineClosure(..) => Err(NoSolution),
 
+        // only when `coroutine_clone` is enabled and the coroutine is movable
+        // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
         ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) {
             Movability::Static => Err(NoSolution),
             Movability::Movable => {
@@ -217,6 +226,7 @@
             }
         },
 
+        // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .tcx()
             .coroutine_hidden_types(def_id)
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 281f5cc..c252ad7 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -250,6 +250,7 @@
     ) -> QueryResult<'tcx> {
         let self_ty = goal.predicate.self_ty();
         match goal.predicate.polarity {
+            // impl FnPtr for FnPtr {}
             ty::ImplPolarity::Positive => {
                 if self_ty.is_fn_ptr() {
                     ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@@ -257,6 +258,7 @@
                     Err(NoSolution)
                 }
             }
+            //  impl !FnPtr for T where T != FnPtr && T is rigid {}
             ty::ImplPolarity::Negative => {
                 // If a type is rigid and not a fn ptr, then we know for certain
                 // that it does *not* implement `FnPtr`.
@@ -374,6 +376,12 @@
         }
     }
 
+    /// ```rust, ignore (not valid rust syntax)
+    /// impl Tuple for () {}
+    /// impl Tuple for (T1,) {}
+    /// impl Tuple for (T1, T2) {}
+    /// impl Tuple for (T1, .., Tn) {}
+    /// ```
     fn consider_builtin_tuple_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 126bc0c..745ddfc 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -91,7 +91,7 @@
     /// Used to set on_unimplemented's `ItemContext`
     /// to be the enclosing (async) block/function/closure
     fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> {
-        match self.tcx.opt_hir_node_by_def_id(def_id)? {
+        match self.tcx.hir_node_by_def_id(def_id) {
             hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) => Some("a function"),
             hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
                 Some("a trait method")
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 1241227..067ca88 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -261,7 +261,8 @@
 
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
         //        don't suggest `T: Sized + ?Sized`.
-        while let Some(node) = self.tcx.opt_hir_node_by_def_id(body_id) {
+        loop {
+            let node = self.tcx.hir_node_by_def_id(body_id);
             match node {
                 hir::Node::Item(hir::Item {
                     ident,
@@ -763,7 +764,7 @@
 
         let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);
         match self.tcx.parent_hir_node(hir_id) {
-            hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. }) => {
+            hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(local), .. }) => {
                 get_name(err, &local.pat.kind)
             }
             // Different to previous arm because one is `&hir::Local` and the other
@@ -987,10 +988,6 @@
             else {
                 return false;
             };
-            let arg_node = self.tcx.hir_node(*arg_hir_id);
-            let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else {
-                return false;
-            };
 
             let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
             let has_clone = |ty| {
@@ -998,6 +995,39 @@
                     .must_apply_modulo_regions()
             };
 
+            let existing_clone_call = match self.tcx.hir_node(*arg_hir_id) {
+                // It's just a variable. Propose cloning it.
+                Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) => None,
+                // It's already a call to `clone()`. We might be able to suggest
+                // adding a `+ Clone` bound, though.
+                Node::Expr(Expr {
+                    kind:
+                        hir::ExprKind::MethodCall(
+                            hir::PathSegment { ident, .. },
+                            _receiver,
+                            &[],
+                            call_span,
+                        ),
+                    hir_id,
+                    ..
+                }) if ident.name == sym::clone
+                    && !call_span.from_expansion()
+                    && !has_clone(*inner_ty) =>
+                {
+                    // We only care about method calls corresponding to the real `Clone` trait.
+                    let Some(typeck_results) = self.typeck_results.as_ref() else { return false };
+                    let Some((DefKind::AssocFn, did)) = typeck_results.type_dependent_def(*hir_id)
+                    else {
+                        return false;
+                    };
+                    if self.tcx.trait_of_item(did) != Some(clone_trait) {
+                        return false;
+                    }
+                    Some(ident.span)
+                }
+                _ => return false,
+            };
+
             let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                 obligation.param_env,
                 trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
@@ -1015,12 +1045,23 @@
                         None,
                     );
                 }
-                err.span_suggestion_verbose(
-                    obligation.cause.span.shrink_to_hi(),
-                    "consider using clone here",
-                    ".clone()".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
+                if let Some(existing_clone_call) = existing_clone_call {
+                    err.span_note(
+                        existing_clone_call,
+                        format!(
+                            "this `clone()` copies the reference, \
+                            which does not do anything, \
+                            because `{inner_ty}` does not implement `Clone`"
+                        ),
+                    );
+                } else {
+                    err.span_suggestion_verbose(
+                        obligation.cause.span.shrink_to_hi(),
+                        "consider using clone here",
+                        ".clone()".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 return true;
             }
             false
@@ -1685,8 +1726,8 @@
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         let hir = self.tcx.hir();
-        let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id);
-        if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
+        let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
+        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = node
             && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
             && sig.decl.output.span().overlaps(span)
             && blk.expr.is_none()
@@ -1720,8 +1761,8 @@
     }
 
     fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
-        let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) =
-            self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id)
+        let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. }) =
+            self.tcx.hir_node_by_def_id(obligation.cause.body_id)
         else {
             return None;
         };
@@ -1813,10 +1854,8 @@
         }
 
         let hir = self.tcx.hir();
-        let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id);
-        if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
-            node
-        {
+        let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
+        if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) = node {
             let body = hir.body(*body_id);
             // Point at all the `return`s in the function as they have failed trait bounds.
             let mut visitor = ReturnsVisitor::default();
@@ -4450,7 +4489,7 @@
             }
             return;
         };
-        let Some(hir::Node::TraitItem(item)) = self.tcx.opt_hir_node_by_def_id(fn_def_id) else {
+        let hir::Node::TraitItem(item) = self.tcx.hir_node_by_def_id(fn_def_id) else {
             return;
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index ad5b7de..4bc3ff9 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -2497,11 +2497,11 @@
                         err.code(E0790);
 
                         if let Some(local_def_id) = data.trait_ref.def_id.as_local()
-                            && let Some(hir::Node::Item(hir::Item {
+                            && let hir::Node::Item(hir::Item {
                                 ident: trait_name,
                                 kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
                                 ..
-                            })) = self.tcx.opt_hir_node_by_def_id(local_def_id)
+                            }) = self.tcx.hir_node_by_def_id(local_def_id)
                             && let Some(method_ref) = trait_item_refs
                                 .iter()
                                 .find(|item_ref| item_ref.ident == *assoc_item_name)
@@ -3073,23 +3073,30 @@
                 let src = trait_ref.args.type_at(1);
                 let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
                 let safe_transmute_explanation = match reason {
-                    rustc_transmute::Reason::SrcIsUnspecified => {
-                        format!("`{src}` does not have a well-specified layout")
+                    rustc_transmute::Reason::SrcIsNotYetSupported => {
+                        format!("analyzing the transmutability of `{src}` is not yet supported.")
                     }
 
-                    rustc_transmute::Reason::DstIsUnspecified => {
-                        format!("`{dst}` does not have a well-specified layout")
+                    rustc_transmute::Reason::DstIsNotYetSupported => {
+                        format!("analyzing the transmutability of `{dst}` is not yet supported.")
                     }
 
                     rustc_transmute::Reason::DstIsBitIncompatible => {
-                        format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
+                        format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
                     }
 
                     rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
                         format!("`{dst}` may carry safety invariants")
                     }
                     rustc_transmute::Reason::DstIsTooBig => {
-                        format!("The size of `{src}` is smaller than the size of `{dst}`")
+                        format!("the size of `{src}` is smaller than the size of `{dst}`")
+                    }
+                    rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
+                        let src_size = src.size;
+                        let dst_size = dst.size;
+                        format!(
+                            "the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
+                        )
                     }
                     rustc_transmute::Reason::SrcSizeOverflow => {
                         format!(
@@ -3106,7 +3113,7 @@
                         dst_min_align,
                     } => {
                         format!(
-                            "The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
+                            "the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
                         )
                     }
                     rustc_transmute::Reason::DstIsMoreUnique => {
@@ -3402,6 +3409,8 @@
         self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err)
     }
 
+    // FIXME(@lcnr): This function could be changed to trait `TraitRef` directly
+    // instead of using a `Binder`.
     fn report_signature_mismatch_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 89654ed..49091e5 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -165,7 +165,6 @@
             let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
             let placeholder_trait_predicate =
                 self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);
-            debug!(?placeholder_trait_predicate);
 
             // The bounds returned by `item_bounds` may contain duplicates after
             // normalization, so try to deduplicate when possible to avoid
@@ -184,8 +183,8 @@
                     selcx.infcx.probe(|_| {
                         match selcx.match_normalize_trait_ref(
                             obligation,
-                            bound.to_poly_trait_ref(),
                             placeholder_trait_predicate.trait_ref,
+                            bound.to_poly_trait_ref(),
                         ) {
                             Ok(None) => {
                                 candidates.vec.push(ProjectionCandidate(idx));
@@ -881,8 +880,8 @@
                         self.infcx.probe(|_| {
                             self.match_normalize_trait_ref(
                                 obligation,
-                                upcast_trait_ref,
                                 placeholder_trait_predicate.trait_ref,
+                                upcast_trait_ref,
                             )
                             .is_ok()
                         })
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 70f6b24..51fc223 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -9,7 +9,7 @@
 use rustc_ast::Mutability;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
+use rustc_infer::infer::HigherRankedType;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
 use rustc_middle::ty::{
@@ -161,8 +161,6 @@
         let placeholder_trait_predicate =
             self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref;
         let placeholder_self_ty = placeholder_trait_predicate.self_ty();
-        let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
-
         let candidate_predicate = self
             .for_each_item_bound(
                 placeholder_self_ty,
@@ -182,6 +180,11 @@
             .expect("projection candidate is not a trait predicate")
             .map_bound(|t| t.trait_ref);
 
+        let candidate = self.infcx.instantiate_binder_with_fresh_vars(
+            obligation.cause.span,
+            HigherRankedType,
+            candidate,
+        );
         let mut obligations = Vec::new();
         let candidate = normalize_with_depth_to(
             self,
@@ -195,7 +198,7 @@
         obligations.extend(
             self.infcx
                 .at(&obligation.cause, obligation.param_env)
-                .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
+                .eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
                 .map(|InferOk { obligations, .. }| obligations)
                 .map_err(|_| Unimplemented)?,
         );
@@ -499,7 +502,6 @@
 
         let trait_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
-        let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
         let ty::Dynamic(data, ..) = *self_ty.kind() else {
             span_bug!(obligation.cause.span, "object candidate with non-object");
         };
@@ -520,19 +522,24 @@
         let unnormalized_upcast_trait_ref =
             supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
 
+        let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
+            obligation.cause.span,
+            HigherRankedType,
+            unnormalized_upcast_trait_ref,
+        );
         let upcast_trait_ref = normalize_with_depth_to(
             self,
             obligation.param_env,
             obligation.cause.clone(),
             obligation.recursion_depth + 1,
-            unnormalized_upcast_trait_ref,
+            upcast_trait_ref,
             &mut nested,
         );
 
         nested.extend(
             self.infcx
                 .at(&obligation.cause, obligation.param_env)
-                .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref)
+                .eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref)
                 .map(|InferOk { obligations, .. }| obligations)
                 .map_err(|_| Unimplemented)?,
         );
@@ -1021,7 +1028,13 @@
         obligation: &PolyTraitObligation<'tcx>,
         self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
+        let obligation_trait_ref =
+            self.infcx.enter_forall_and_leak_universe(obligation.predicate.to_poly_trait_ref());
+        let self_ty_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
+            obligation.cause.span,
+            HigherRankedType,
+            self_ty_trait_ref,
+        );
         // Normalize the obligation and expected trait refs together, because why not
         let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
             ensure_sufficient_stack(|| {
@@ -1037,15 +1050,15 @@
         // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
+            .eq(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref)
             .map(|InferOk { mut obligations, .. }| {
                 obligations.extend(nested);
                 obligations
             })
             .map_err(|terr| {
                 SignatureMismatch(Box::new(SignatureMismatchData {
-                    expected_trait_ref: obligation_trait_ref,
-                    found_trait_ref: expected_trait_ref,
+                    expected_trait_ref: ty::Binder::dummy(obligation_trait_ref),
+                    found_trait_ref: ty::Binder::dummy(expected_trait_ref),
                     terr,
                 }))
             })
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a6bd1ba..d10fe6a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -33,6 +33,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::BoundRegionConversionTime;
+use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::TraitObligation;
 use rustc_middle::dep_graph::dep_kinds;
@@ -42,7 +43,7 @@
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
+use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
@@ -1651,15 +1652,20 @@
     fn match_normalize_trait_ref(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-        trait_bound: ty::PolyTraitRef<'tcx>,
         placeholder_trait_ref: ty::TraitRef<'tcx>,
-    ) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
+        trait_bound: ty::PolyTraitRef<'tcx>,
+    ) -> Result<Option<ty::TraitRef<'tcx>>, ()> {
         debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
         if placeholder_trait_ref.def_id != trait_bound.def_id() {
             // Avoid unnecessary normalization
             return Err(());
         }
 
+        let trait_bound = self.infcx.instantiate_binder_with_fresh_vars(
+            obligation.cause.span,
+            HigherRankedType,
+            trait_bound,
+        );
         let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
             normalize_with_depth(
                 self,
@@ -1671,7 +1677,7 @@
         });
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound)
+            .eq(DefineOpaqueTypes::No, placeholder_trait_ref, trait_bound)
             .map(|InferOk { obligations: _, value: () }| {
                 // This method is called within a probe, so we can't have
                 // inference variables and placeholders escape.
@@ -1683,7 +1689,6 @@
             })
             .map_err(|_| ())
     }
-
     fn where_clause_may_apply<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -1733,7 +1738,7 @@
         let is_match = self
             .infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
+            .eq(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
             .is_ok_and(|InferOk { obligations, value: () }| {
                 self.evaluate_predicates_recursively(
                     TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -2533,7 +2538,7 @@
                     nested.extend(
                         self.infcx
                             .at(&obligation.cause, obligation.param_env)
-                            .sup(
+                            .eq(
                                 DefineOpaqueTypes::No,
                                 upcast_principal.map_bound(|trait_ref| {
                                     ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
@@ -2571,7 +2576,7 @@
                     nested.extend(
                         self.infcx
                             .at(&obligation.cause, obligation.param_env)
-                            .sup(DefineOpaqueTypes::No, source_projection, target_projection)
+                            .eq(DefineOpaqueTypes::No, source_projection, target_projection)
                             .map_err(|_| SelectionError::Unimplemented)?
                             .into_obligations(),
                     );
@@ -2615,9 +2620,15 @@
         obligation: &PolyTraitObligation<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+        let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
+        let trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
+            obligation.cause.span,
+            HigherRankedType,
+            poly_trait_ref,
+        );
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+            .eq(DefineOpaqueTypes::No, predicate.trait_ref, trait_ref)
             .map(|InferOk { obligations, .. }| obligations)
             .map_err(|_| ())
     }
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 3c0316f..46a6850 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -320,6 +320,7 @@
 }
 
 /// Find slot base for trait methods within vtable entries of another trait
+// FIXME(@lcnr): This isn't a query, so why does it take a tuple as its argument.
 pub(super) fn vtable_trait_first_method_offset<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: (
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index f89daf0..64f02bf 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -164,7 +164,7 @@
             wf.compute(ty.into());
         }
         ty::ClauseKind::Projection(t) => {
-            wf.compute_projection(t.projection_ty);
+            wf.compute_alias(t.projection_ty);
             wf.compute(match t.term.unpack() {
                 ty::TermKind::Ty(ty) => ty.into(),
                 ty::TermKind::Const(c) => c.into(),
@@ -436,9 +436,9 @@
         }
     }
 
-    /// Pushes the obligations required for `trait_ref::Item` to be WF
+    /// Pushes the obligations required for an alias (except inherent) to be WF
     /// into `self.out`.
-    fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) {
+    fn compute_alias(&mut self, data: ty::AliasTy<'tcx>) {
         // A projection is well-formed if
         //
         // (a) its predicates hold (*)
@@ -466,6 +466,9 @@
         self.compute_projection_args(data.args);
     }
 
+    /// Pushes the obligations required for an inherent alias to be WF
+    /// into `self.out`.
+    // FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
     fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
         // An inherent projection is well-formed if
         //
@@ -688,8 +691,8 @@
                 // Simple cases that are WF if their type args are WF.
             }
 
-            ty::Alias(ty::Projection, data) => {
-                self.compute_projection(data);
+            ty::Alias(ty::Projection | ty::Opaque | ty::Weak, data) => {
+                self.compute_alias(data);
                 return; // Subtree handled by compute_projection.
             }
             ty::Alias(ty::Inherent, data) => {
@@ -791,21 +794,6 @@
                 // types appearing in the fn signature.
             }
 
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
-                // All of the requirements on type parameters
-                // have already been checked for `impl Trait` in
-                // return position. We do need to check type-alias-impl-trait though.
-                if self.tcx().is_type_alias_impl_trait(def_id) {
-                    let obligations = self.nominal_obligations(def_id, args);
-                    self.out.extend(obligations);
-                }
-            }
-
-            ty::Alias(ty::Weak, ty::AliasTy { def_id, args, .. }) => {
-                let obligations = self.nominal_obligations(def_id, args);
-                self.out.extend(obligations);
-            }
-
             ty::Dynamic(data, r, _) => {
                 // WfObject
                 //
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index 0441b49..a7c60c3 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -35,6 +35,8 @@
 pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {
     fn min_align(&self) -> usize;
 
+    fn size(&self) -> usize;
+
     fn is_mutable(&self) -> bool;
 }
 
@@ -48,6 +50,9 @@
     fn min_align(&self) -> usize {
         unreachable!()
     }
+    fn size(&self) -> usize {
+        unreachable!()
+    }
     fn is_mutable(&self) -> bool {
         unreachable!()
     }
@@ -57,6 +62,7 @@
 pub mod rustc {
     use rustc_middle::mir::Mutability;
     use rustc_middle::ty::{self, Ty};
+    use std::fmt::{self, Write};
 
     /// A reference in the layout.
     #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
@@ -65,6 +71,7 @@
         pub ty: Ty<'tcx>,
         pub mutability: Mutability,
         pub align: usize,
+        pub size: usize,
     }
 
     impl<'tcx> super::Ref for Ref<'tcx> {
@@ -72,6 +79,10 @@
             self.align
         }
 
+        fn size(&self) -> usize {
+            self.size
+        }
+
         fn is_mutable(&self) -> bool {
             match self.mutability {
                 Mutability::Mut => true,
@@ -81,6 +92,16 @@
     }
     impl<'tcx> Ref<'tcx> {}
 
+    impl<'tcx> fmt::Display for Ref<'tcx> {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_char('&')?;
+            if self.mutability == Mutability::Mut {
+                f.write_str("mut ")?;
+            }
+            self.ty.fmt(f)
+        }
+    }
+
     /// A visibility node in the layout.
     #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
     pub enum Def<'tcx> {
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 71b7282..9a43d67 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -186,8 +186,8 @@
 
     #[derive(Debug, Copy, Clone)]
     pub(crate) enum Err {
-        /// The layout of the type is unspecified.
-        Unspecified,
+        /// The layout of the type is not yet supported.
+        NotYetSupported,
         /// This error will be surfaced elsewhere by rustc, so don't surface it.
         UnknownLayout,
         /// Overflow size
@@ -288,14 +288,14 @@
                     if members.len() == 0 {
                         Ok(Tree::unit())
                     } else {
-                        Err(Err::Unspecified)
+                        Err(Err::NotYetSupported)
                     }
                 }
 
                 ty::Array(ty, len) => {
                     let len = len
                         .try_eval_target_usize(tcx, ParamEnv::reveal_all())
-                        .ok_or(Err::Unspecified)?;
+                        .ok_or(Err::NotYetSupported)?;
                     let elt = Tree::from_ty(*ty, tcx)?;
                     Ok(std::iter::repeat(elt)
                         .take(len as usize)
@@ -307,7 +307,7 @@
 
                     // If the layout is ill-specified, halt.
                     if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
-                        return Err(Err::Unspecified);
+                        return Err(Err::NotYetSupported);
                     }
 
                     // Compute a summary of the type's layout.
@@ -348,7 +348,7 @@
                         AdtKind::Union => {
                             // is the layout well-defined?
                             if !adt_def.repr().c() {
-                                return Err(Err::Unspecified);
+                                return Err(Err::NotYetSupported);
                             }
 
                             let ty_layout = layout_of(tcx, ty)?;
@@ -372,16 +372,19 @@
                 }
 
                 ty::Ref(lifetime, ty, mutability) => {
-                    let align = layout_of(tcx, *ty)?.align();
+                    let layout = layout_of(tcx, *ty)?;
+                    let align = layout.align();
+                    let size = layout.size();
                     Ok(Tree::Ref(Ref {
                         lifetime: *lifetime,
                         ty: *ty,
                         mutability: *mutability,
                         align,
+                        size,
                     }))
                 }
 
-                _ => Err(Err::Unspecified),
+                _ => Err(Err::NotYetSupported),
             }
         }
 
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index fefce26..e871c46 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -23,7 +23,7 @@
 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
 pub enum Answer<R> {
     Yes,
-    No(Reason),
+    No(Reason<R>),
     If(Condition<R>),
 }
 
@@ -42,17 +42,24 @@
 
 /// Answers "why wasn't the source type transmutable into the destination type?"
 #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
-pub enum Reason {
-    /// The layout of the source type is unspecified.
-    SrcIsUnspecified,
-    /// The layout of the destination type is unspecified.
-    DstIsUnspecified,
+pub enum Reason<T> {
+    /// The layout of the source type is not yet supported.
+    SrcIsNotYetSupported,
+    /// The layout of the destination type is not yet supported.
+    DstIsNotYetSupported,
     /// The layout of the destination type is bit-incompatible with the source type.
     DstIsBitIncompatible,
     /// The destination type may carry safety invariants.
     DstMayHaveSafetyInvariants,
     /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
     DstIsTooBig,
+    /// A referent of `Dst` is larger than a referent in `Src`.
+    DstRefIsTooBig {
+        /// The referent of the source type.
+        src: T,
+        /// The too-large referent of the destination type.
+        dst: T,
+    },
     /// Src should have a stricter alignment than Dst, but it does not.
     DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
     /// Can't go from shared pointer to unique pointer
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 0e05aa4..16d1558 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -56,8 +56,8 @@
                 }
                 (Err(Err::UnknownLayout), _) => Answer::No(Reason::SrcLayoutUnknown),
                 (_, Err(Err::UnknownLayout)) => Answer::No(Reason::DstLayoutUnknown),
-                (Err(Err::Unspecified), _) => Answer::No(Reason::SrcIsUnspecified),
-                (_, Err(Err::Unspecified)) => Answer::No(Reason::DstIsUnspecified),
+                (Err(Err::NotYetSupported), _) => Answer::No(Reason::SrcIsNotYetSupported),
+                (_, Err(Err::NotYetSupported)) => Answer::No(Reason::DstIsNotYetSupported),
                 (Err(Err::SizeOverflow), _) => Answer::No(Reason::SrcSizeOverflow),
                 (_, Err(Err::SizeOverflow)) => Answer::No(Reason::DstSizeOverflow),
                 (Ok(src), Ok(dst)) => MaybeTransmutableQuery { src, dst, assume, context }.answer(),
@@ -266,6 +266,11 @@
                                                 src_min_align: src_ref.min_align(),
                                                 dst_min_align: dst_ref.min_align(),
                                             })
+                                        } else if dst_ref.size() > src_ref.size() {
+                                            Answer::No(Reason::DstRefIsTooBig {
+                                                src: src_ref,
+                                                dst: dst_ref,
+                                            })
                                         } else {
                                             // ...such that `src` is transmutable into `dst`, if
                                             // `src_ref` is transmutability into `dst_ref`.
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 26d3370..50a8eb8 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -1,10 +1,11 @@
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{self as hir, HirId};
+use rustc_index::IndexVec;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
+use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt, TyCtxtFeed};
 use rustc_span::symbol::kw;
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -237,6 +238,28 @@
     }
 }
 
+fn feed_hir(feed: &TyCtxtFeed<'_, LocalDefId>) {
+    feed.local_def_id_to_hir_id(HirId::make_owner(feed.def_id()));
+
+    let node = hir::OwnerNode::AssocOpaqueTy(&hir::AssocOpaqueTy {});
+    let bodies = Default::default();
+    let attrs = hir::AttributeMap::EMPTY;
+
+    let (opt_hash_including_bodies, _) = feed.tcx.hash_owner_nodes(node, &bodies, &attrs.map);
+    feed.opt_hir_owner_nodes(Some(feed.tcx.arena.alloc(hir::OwnerNodes {
+        opt_hash_including_bodies,
+        nodes: IndexVec::from_elem_n(
+            hir::ParentedNode {
+                parent: hir::ItemLocalId::INVALID,
+                node: hir::Node::AssocOpaqueTy(&hir::AssocOpaqueTy {}),
+            },
+            1,
+        ),
+        bodies,
+    })));
+    feed.feed_owner_id().hir_attrs(attrs);
+}
+
 /// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
 /// function from a trait, synthesize an associated type for that `impl Trait`
 /// that inherits properties that we infer from the method and the opaque type.
@@ -258,9 +281,7 @@
     let local_def_id = trait_assoc_ty.def_id();
     let def_id = local_def_id.to_def_id();
 
-    // There's no HIR associated with this new synthesized `def_id`, so feed
-    // `opt_local_def_id_to_hir_id` with `None`.
-    trait_assoc_ty.opt_local_def_id_to_hir_id(None);
+    feed_hir(&trait_assoc_ty);
 
     // Copy span of the opaque.
     trait_assoc_ty.def_ident_span(Some(span));
@@ -304,11 +325,7 @@
 ) -> LocalDefId {
     let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
 
-    let decl = tcx
-        .opt_hir_node_by_def_id(impl_fn_def_id)
-        .expect("expected item")
-        .fn_decl()
-        .expect("expected decl");
+    let decl = tcx.hir_node_by_def_id(impl_fn_def_id).fn_decl().expect("expected decl");
     let span = match decl.output {
         hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id),
         hir::FnRetTy::Return(ty) => ty.span,
@@ -318,9 +335,7 @@
     let local_def_id = impl_assoc_ty.def_id();
     let def_id = local_def_id.to_def_id();
 
-    // There's no HIR associated with this new synthesized `def_id`, so feed
-    // `opt_local_def_id_to_hir_id` with `None`.
-    impl_assoc_ty.opt_local_def_id_to_hir_id(None);
+    feed_hir(&impl_assoc_ty);
 
     // Copy span of the opaque.
     impl_assoc_ty.def_ident_span(Some(span));
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
index 7fda9ce..92bc2e3 100644
--- a/compiler/stable_mir/src/abi.rs
+++ b/compiler/stable_mir/src/abi.rs
@@ -383,7 +383,7 @@
             return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits()));
         };
         if self.start <= max_value && self.end <= max_value {
-            Ok(self.start == 0 && max_value == self.end)
+            Ok(self.start == (self.end.wrapping_add(1) & max_value))
         } else {
             Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits()))
         }
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index 1c51c17..f53dbcf 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -14,7 +14,7 @@
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
     ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics,
     ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, TyKind,
-    VariantDef,
+    UintTy, VariantDef,
 };
 use crate::{
     mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
@@ -101,8 +101,17 @@
     /// Evaluate constant as a target usize.
     fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
 
-    /// Create a target usize constant for the given value.
-    fn usize_to_const(&self, val: u64) -> Result<Const, Error>;
+    /// Create a new zero-sized constant.
+    fn try_new_const_zst(&self, ty: Ty) -> Result<Const, Error>;
+
+    /// Create a new constant that represents the given string value.
+    fn new_const_str(&self, value: &str) -> Const;
+
+    /// Create a new constant that represents the given boolean value.
+    fn new_const_bool(&self, value: bool) -> Const;
+
+    /// Create a new constant that represents the given value.
+    fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<Const, Error>;
 
     /// Create a new type from the given kind.
     fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
@@ -200,7 +209,7 @@
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
 // datastructures and stable MIR datastructures
-scoped_thread_local! (static TLV: Cell<*const ()>);
+scoped_thread_local!(static TLV: Cell<*const ()>);
 
 pub fn run<F, T>(context: &dyn Context, f: F) -> Result<T, Error>
 where
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 86cc748..a337675 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -128,13 +128,38 @@
 
     /// Creates an interned usize constant.
     fn try_from_target_usize(val: u64) -> Result<Self, Error> {
-        with(|cx| cx.usize_to_const(val))
+        with(|cx| cx.try_new_const_uint(val.into(), UintTy::Usize))
     }
 
     /// Try to evaluate to a target `usize`.
     pub fn eval_target_usize(&self) -> Result<u64, Error> {
         with(|cx| cx.eval_target_usize(self))
     }
+
+    /// Create a constant that represents a new zero-sized constant of type T.
+    /// Fails if the type is not a ZST or if it doesn't have a known size.
+    pub fn try_new_zero_sized(ty: Ty) -> Result<Const, Error> {
+        with(|cx| cx.try_new_const_zst(ty))
+    }
+
+    /// Build a new constant that represents the given string.
+    ///
+    /// Note that there is no guarantee today about duplication of the same constant.
+    /// I.e.: Calling this function multiple times with the same argument may or may not return
+    /// the same allocation.
+    pub fn from_str(value: &str) -> Const {
+        with(|cx| cx.new_const_str(value))
+    }
+
+    /// Build a new constant that represents the given boolean value.
+    pub fn from_bool(value: bool) -> Const {
+        with(|cx| cx.new_const_bool(value))
+    }
+
+    /// Build a new constant that represents the given unsigned integer.
+    pub fn try_from_uint(value: u128, uint_ty: UintTy) -> Result<Const, Error> {
+        with(|cx| cx.try_new_const_uint(value, uint_ty))
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
diff --git a/library/backtrace b/library/backtrace
index ddf1b89..6fa4b85 160000
--- a/library/backtrace
+++ b/library/backtrace
@@ -1 +1 @@
-Subproject commit ddf1b89b861d297c6ef3f09b70d853e81ccc85ff
+Subproject commit 6fa4b85b9962c3e1be8c2e5cc605cd078134152b
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 111fb83..30debbf 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -5,8 +5,11 @@
 use crate::ffi::c_char;
 use crate::fmt;
 use crate::intrinsics;
+use crate::iter::FusedIterator;
+use crate::marker::PhantomData;
 use crate::ops;
 use crate::ptr::addr_of;
+use crate::ptr::NonNull;
 use crate::slice;
 use crate::slice::memchr;
 use crate::str;
@@ -504,6 +507,13 @@
         self.inner.as_ptr()
     }
 
+    /// We could eventually expose this publicly, if we wanted.
+    #[inline]
+    #[must_use]
+    const fn as_non_null_ptr(&self) -> NonNull<c_char> {
+        NonNull::from(&self.inner).as_non_null_ptr()
+    }
+
     /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator.
     ///
     /// > **Note**: This method is currently implemented as a constant-time
@@ -617,6 +627,26 @@
         unsafe { &*(addr_of!(self.inner) as *const [u8]) }
     }
 
+    /// Iterates over the bytes in this C string.
+    ///
+    /// The returned iterator will **not** contain the trailing nul terminator
+    /// that this C string has.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cstr_bytes)]
+    /// use std::ffi::CStr;
+    ///
+    /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+    /// assert!(cstr.bytes().eq(*b"foo"));
+    /// ```
+    #[inline]
+    #[unstable(feature = "cstr_bytes", issue = "112115")]
+    pub fn bytes(&self) -> Bytes<'_> {
+        Bytes::new(self)
+    }
+
     /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
     ///
     /// If the contents of the `CStr` are valid UTF-8 data, this
@@ -735,3 +765,64 @@
         intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt)
     }
 }
+
+/// An iterator over the bytes of a [`CStr`], without the nul terminator.
+///
+/// This struct is created by the [`bytes`] method on [`CStr`].
+/// See its documentation for more.
+///
+/// [`bytes`]: CStr::bytes
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "cstr_bytes", issue = "112115")]
+#[derive(Clone, Debug)]
+pub struct Bytes<'a> {
+    // since we know the string is nul-terminated, we only need one pointer
+    ptr: NonNull<u8>,
+    phantom: PhantomData<&'a u8>,
+}
+impl<'a> Bytes<'a> {
+    #[inline]
+    fn new(s: &'a CStr) -> Self {
+        Self { ptr: s.as_non_null_ptr().cast(), phantom: PhantomData }
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        // SAFETY: We uphold that the pointer is always valid to dereference
+        // by starting with a valid C string and then never incrementing beyond
+        // the nul terminator.
+        unsafe { self.ptr.read() == 0 }
+    }
+}
+
+#[unstable(feature = "cstr_bytes", issue = "112115")]
+impl Iterator for Bytes<'_> {
+    type Item = u8;
+
+    #[inline]
+    fn next(&mut self) -> Option<u8> {
+        // SAFETY: We only choose a pointer from a valid C string, which must
+        // be non-null and contain at least one value. Since we always stop at
+        // the nul terminator, which is guaranteed to exist, we can assume that
+        // the pointer is non-null and valid. This lets us safely dereference
+        // it and assume that adding 1 will create a new, non-null, valid
+        // pointer.
+        unsafe {
+            let ret = self.ptr.read();
+            if ret == 0 {
+                None
+            } else {
+                self.ptr = self.ptr.offset(1);
+                Some(ret)
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.is_empty() { (0, Some(0)) } else { (1, None) }
+    }
+}
+
+#[unstable(feature = "cstr_bytes", issue = "112115")]
+impl FusedIterator for Bytes<'_> {}
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 6893716..055ead1 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -22,7 +22,7 @@
 ///
 /// The *successor* operation moves towards values that compare greater.
 /// The *predecessor* operation moves towards values that compare lesser.
-#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
+#[unstable(feature = "step_trait", issue = "42168")]
 pub trait Step: Clone + PartialOrd + Sized {
     /// Returns the number of *successor* steps required to get from `start` to `end`.
     ///
@@ -52,15 +52,12 @@
     /// For any `a`, `n`, and `m`:
     ///
     /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))`
-    ///
-    /// For any `a`, `n`, and `m` where `n + m` does not overflow:
-    ///
-    /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)`
+    /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == try { Step::forward_checked(a, n.checked_add(m)) }`
     ///
     /// For any `a` and `n`:
     ///
     /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
-    ///   * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
+    ///   * Corollary: `Step::forward_checked(a, 0) == Some(a)`
     fn forward_checked(start: Self, count: usize) -> Option<Self>;
 
     /// Returns the value that would be obtained by taking the *successor*
@@ -106,6 +103,7 @@
     /// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)`
     /// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`,
     ///   it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`.
+    ///   * Corollary: `Step::forward_unchecked(a, 0)` is always safe.
     ///
     /// For any `a` and `n`, where no overflow occurs:
     ///
@@ -128,8 +126,8 @@
     ///
     /// For any `a` and `n`:
     ///
-    /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
-    ///   * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
+    /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(x, 1))`
+    ///   * Corollary: `Step::backward_checked(a, 0) == Some(a)`
     fn backward_checked(start: Self, count: usize) -> Option<Self>;
 
     /// Returns the value that would be obtained by taking the *predecessor*
@@ -175,6 +173,7 @@
     /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
     /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
     ///   it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
+    ///   * Corollary: `Step::backward_unchecked(a, 0)` is always safe.
     ///
     /// For any `a` and `n`, where no overflow occurs:
     ///
@@ -184,8 +183,25 @@
     }
 }
 
-// These are still macro-generated because the integer literals resolve to different types.
-macro_rules! step_identical_methods {
+// Separate impls for signed ranges because the distance within a signed range can be larger
+// than the signed::MAX value. Therefore `as` casting to the signed type would be incorrect.
+macro_rules! step_signed_methods {
+    ($unsigned: ty) => {
+        #[inline]
+        unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
+            // SAFETY: the caller has to guarantee that `start + n` doesn't overflow.
+            unsafe { start.checked_add_unsigned(n as $unsigned).unwrap_unchecked() }
+        }
+
+        #[inline]
+        unsafe fn backward_unchecked(start: Self, n: usize) -> Self {
+            // SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
+            unsafe { start.checked_sub_unsigned(n as $unsigned).unwrap_unchecked() }
+        }
+    };
+}
+
+macro_rules! step_unsigned_methods {
     () => {
         #[inline]
         unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
@@ -198,7 +214,12 @@
             // SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
             unsafe { start.unchecked_sub(n as Self) }
         }
+    };
+}
 
+// These are still macro-generated because the integer literals resolve to different types.
+macro_rules! step_identical_methods {
+    () => {
         #[inline]
         #[allow(arithmetic_overflow)]
         #[rustc_inherit_overflow_checks]
@@ -239,6 +260,7 @@
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
             impl Step for $u_narrower {
                 step_identical_methods!();
+                step_unsigned_methods!();
 
                 #[inline]
                 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
@@ -271,6 +293,7 @@
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
             impl Step for $i_narrower {
                 step_identical_methods!();
+                step_signed_methods!($u_narrower);
 
                 #[inline]
                 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
@@ -335,6 +358,7 @@
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
             impl Step for $u_wider {
                 step_identical_methods!();
+                step_unsigned_methods!();
 
                 #[inline]
                 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
@@ -360,6 +384,7 @@
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
             impl Step for $i_wider {
                 step_identical_methods!();
+                step_signed_methods!($u_wider);
 
                 #[inline]
                 fn steps_between(start: &Self, end: &Self) -> Option<usize> {
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index b533f53..78494b8 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -856,6 +856,48 @@
         (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32)
     }
 
+    /// Returns the number of milliseconds contained by this `Duration` as `f64`.
+    ///
+    /// The returned value does include the fractional (nanosecond) part of the duration.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_millis_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::new(2, 345_678_000);
+    /// assert_eq!(dur.as_millis_f64(), 2345.678);
+    /// ```
+    #[unstable(feature = "duration_millis_float", issue = "122451")]
+    #[must_use]
+    #[inline]
+    #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
+    pub const fn as_millis_f64(&self) -> f64 {
+        (self.secs as f64) * (MILLIS_PER_SEC as f64)
+            + (self.nanos.0 as f64) / (NANOS_PER_MILLI as f64)
+    }
+
+    /// Returns the number of milliseconds contained by this `Duration` as `f32`.
+    ///
+    /// The returned value does include the fractional (nanosecond) part of the duration.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_millis_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::new(2, 345_678_000);
+    /// assert_eq!(dur.as_millis_f32(), 2345.678);
+    /// ```
+    #[unstable(feature = "duration_millis_float", issue = "122451")]
+    #[must_use]
+    #[inline]
+    #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
+    pub const fn as_millis_f32(&self) -> f32 {
+        (self.secs as f32) * (MILLIS_PER_SEC as f32)
+            + (self.nanos.0 as f32) / (NANOS_PER_MILLI as f32)
+    }
+
     /// Creates a new `Duration` from the specified number of seconds represented
     /// as `f64`.
     ///
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
index 9af0711..e31db07 100644
--- a/library/core/tests/iter/range.rs
+++ b/library/core/tests/iter/range.rs
@@ -325,6 +325,11 @@
     assert_eq!(Ok(()), r.advance_back_by(usize::MAX));
 
     assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128));
+
+    // issue 122420, Step::forward_unchecked was unsound for signed integers
+    let mut r = -128i8..127;
+    assert_eq!(Ok(()), r.advance_by(200));
+    assert_eq!(r.next(), Some(72));
 }
 
 #[test]
diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml
index 3371dfa..937149f 100644
--- a/library/profiler_builtins/Cargo.toml
+++ b/library/profiler_builtins/Cargo.toml
@@ -13,4 +13,4 @@
 compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] }
 
 [build-dependencies]
-cc = "1.0.69"
+cc = "1.0.90"
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index a65e785..65dec38 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1782,6 +1782,7 @@
         }
         let mut addr = c::SOCKADDR_UN { sun_family: c::AF_UNIX, sun_path: mem::zeroed() };
         let bytes = socket_path.as_os_str().as_encoded_bytes();
+        let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::<i8>(), bytes.len());
         addr.sun_path[..bytes.len()].copy_from_slice(bytes);
         let len = mem::size_of_val(&addr) as i32;
         let result = c::bind(socket, ptr::addr_of!(addr).cast::<c::SOCKADDR>(), len);
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 25c6424..4ef1f1b 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -51,6 +51,8 @@
 /// // We might want to use a BufReader here for efficiency, but let's
 /// // keep this example focused.
 /// let mut file = File::create("foo.txt")?;
+/// // First, we need to allocate 10 bytes to be able to write into.
+/// file.set_len(10)?;
 ///
 /// write_ten_bytes_at_end(&mut file)?;
 /// # Ok(())
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 873bfb6..8415f36 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -48,7 +48,7 @@
 
 #[doc(keyword = "break")]
 //
-/// Exit early from a loop.
+/// Exit early from a loop or labelled block.
 ///
 /// When `break` is encountered, execution of the associated loop body is
 /// immediately terminated.
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index e45457b..72ea54b 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -39,6 +39,13 @@
     /// Sets the child process's user ID. This translates to a
     /// `setuid` call in the child process. Failure in the `setuid`
     /// call will cause the spawn to fail.
+    ///
+    /// # Notes
+    ///
+    /// This will also trigger a call to `setgroups(0, NULL)` in the child
+    /// process if no groups have been specified.
+    /// This removes supplementary groups that might have given the child
+    /// unwanted permissions.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn uid(&mut self, id: UserId) -> &mut process::Command;
 
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index d04804a..a9d1983 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -7,7 +7,7 @@
 use crate::fs;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::mem::forget;
+use crate::mem::{forget, ManuallyDrop};
 use crate::ptr;
 use crate::sys;
 use crate::sys::cvt;
@@ -91,7 +91,7 @@
 #[repr(transparent)]
 #[stable(feature = "io_safety", since = "1.63.0")]
 #[derive(Debug)]
-pub struct HandleOrNull(OwnedHandle);
+pub struct HandleOrNull(RawHandle);
 
 /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
 /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
@@ -110,7 +110,7 @@
 #[repr(transparent)]
 #[stable(feature = "io_safety", since = "1.63.0")]
 #[derive(Debug)]
-pub struct HandleOrInvalid(OwnedHandle);
+pub struct HandleOrInvalid(RawHandle);
 
 // The Windows [`HANDLE`] type may be transferred across and shared between
 // thread boundaries (despite containing a `*mut void`, which in general isn't
@@ -163,15 +163,24 @@
 
     #[inline]
     fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
-        let owned_handle = handle_or_null.0;
-        if owned_handle.handle.is_null() {
-            // Don't call `CloseHandle`; it'd be harmless, except that it could
-            // overwrite the `GetLastError` error.
-            forget(owned_handle);
-
-            Err(NullHandleError(()))
+        let handle_or_null = ManuallyDrop::new(handle_or_null);
+        if handle_or_null.is_valid() {
+            // SAFETY: The handle is not null.
+            Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_null.0) })
         } else {
-            Ok(owned_handle)
+            Err(NullHandleError(()))
+        }
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for HandleOrNull {
+    #[inline]
+    fn drop(&mut self) {
+        if self.is_valid() {
+            unsafe {
+                let _ = sys::c::CloseHandle(self.0);
+            }
         }
     }
 }
@@ -232,15 +241,24 @@
 
     #[inline]
     fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
-        let owned_handle = handle_or_invalid.0;
-        if owned_handle.handle == sys::c::INVALID_HANDLE_VALUE {
-            // Don't call `CloseHandle`; it'd be harmless, except that it could
-            // overwrite the `GetLastError` error.
-            forget(owned_handle);
-
-            Err(InvalidHandleError(()))
+        let handle_or_invalid = ManuallyDrop::new(handle_or_invalid);
+        if handle_or_invalid.is_valid() {
+            // SAFETY: The handle is not invalid.
+            Ok(unsafe { OwnedHandle::from_raw_handle(handle_or_invalid.0) })
         } else {
-            Ok(owned_handle)
+            Err(InvalidHandleError(()))
+        }
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl Drop for HandleOrInvalid {
+    #[inline]
+    fn drop(&mut self) {
+        if self.is_valid() {
+            unsafe {
+                let _ = sys::c::CloseHandle(self.0);
+            }
         }
     }
 }
@@ -333,7 +351,11 @@
     #[stable(feature = "io_safety", since = "1.63.0")]
     #[inline]
     pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
-        Self(OwnedHandle::from_raw_handle(handle))
+        Self(handle)
+    }
+
+    fn is_valid(&self) -> bool {
+        !self.0.is_null()
     }
 }
 
@@ -356,7 +378,11 @@
     #[stable(feature = "io_safety", since = "1.63.0")]
     #[inline]
     pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
-        Self(OwnedHandle::from_raw_handle(handle))
+        Self(handle)
+    }
+
+    fn is_valid(&self) -> bool {
+        self.0 != sys::c::INVALID_HANDLE_VALUE
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 422a993..b968f8d 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -463,15 +463,15 @@
 #[cfg(target_os = "netbsd")]
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64))
+        SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64)
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64))
+        SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64)
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64))
+        SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64)
     }
 }
 
@@ -503,16 +503,16 @@
         #[cfg(target_pointer_width = "32")]
         cfg_has_statx! {
             if let Some(mtime) = self.stx_mtime() {
-                return Ok(SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64));
+                return SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64);
             }
         }
 
-        Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64))
+        SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64)
     }
 
     #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
+        SystemTime::new(self.stat.st_mtime as i64, 0)
     }
 
     #[cfg(any(target_os = "horizon", target_os = "hurd"))]
@@ -531,16 +531,16 @@
         #[cfg(target_pointer_width = "32")]
         cfg_has_statx! {
             if let Some(atime) = self.stx_atime() {
-                return Ok(SystemTime::new(atime.tv_sec, atime.tv_nsec as i64));
+                return SystemTime::new(atime.tv_sec, atime.tv_nsec as i64);
             }
         }
 
-        Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64))
+        SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64)
     }
 
     #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_atime as i64, 0))
+        SystemTime::new(self.stat.st_atime as i64, 0)
     }
 
     #[cfg(any(target_os = "horizon", target_os = "hurd"))]
@@ -557,7 +557,7 @@
         target_os = "watchos",
     ))]
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
+        SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64)
     }
 
     #[cfg(not(any(
@@ -573,7 +573,7 @@
         cfg_has_statx! {
             if let Some(ext) = &self.statx_extra_fields {
                 return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
-                    Ok(SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64))
+                    SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64)
                 } else {
                     Err(io::const_io_error!(
                         io::ErrorKind::Unsupported,
@@ -592,22 +592,22 @@
 
     #[cfg(target_os = "vita")]
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_ctime as i64, 0))
+        SystemTime::new(self.stat.st_ctime as i64, 0)
     }
 }
 
 #[cfg(target_os = "nto")]
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec))
+        SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec)
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec))
+        SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec)
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec))
+        SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec)
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 97cbd19..f017d39 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -330,14 +330,22 @@
             if let Some(u) = self.get_uid() {
                 // When dropping privileges from root, the `setgroups` call
                 // will remove any extraneous groups. We only drop groups
-                // if the current uid is 0 and we weren't given an explicit
+                // if we have CAP_SETGID and we weren't given an explicit
                 // set of groups. If we don't call this, then even though our
                 // uid has dropped, we may still have groups that enable us to
                 // do super-user things.
                 //FIXME: Redox kernel does not support setgroups yet
                 #[cfg(not(target_os = "redox"))]
-                if libc::getuid() == 0 && self.get_groups().is_none() {
-                    cvt(libc::setgroups(0, crate::ptr::null()))?;
+                if self.get_groups().is_none() {
+                    let res = cvt(libc::setgroups(0, crate::ptr::null()));
+                    if let Err(e) = res {
+                        // Here we ignore the case of not having CAP_SETGID.
+                        // An alternative would be to require CAP_SETGID (in
+                        // addition to CAP_SETUID) for setting the UID.
+                        if e.raw_os_error() != Some(libc::EPERM) {
+                            return Err(e.into());
+                        }
+                    }
                 }
                 cvt(libc::setuid(u as uid_t))?;
             }
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index 251a37d..0440f33 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -1,5 +1,5 @@
-use crate::fmt;
 use crate::time::Duration;
+use crate::{fmt, io};
 
 const NSEC_PER_SEC: u64 = 1_000_000_000;
 pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
@@ -34,8 +34,8 @@
 
 impl SystemTime {
     #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
-    pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
-        SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
+    pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
+        Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
     }
 
     pub fn now() -> SystemTime {
@@ -55,12 +55,6 @@
     }
 }
 
-impl From<libc::timespec> for SystemTime {
-    fn from(t: libc::timespec) -> SystemTime {
-        SystemTime { t: Timespec::from(t) }
-    }
-}
-
 impl fmt::Debug for SystemTime {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SystemTime")
@@ -71,11 +65,15 @@
 }
 
 impl Timespec {
-    pub const fn zero() -> Timespec {
-        Timespec::new(0, 0)
+    const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec {
+        Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
     }
 
-    const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
+    pub const fn zero() -> Timespec {
+        unsafe { Self::new_unchecked(0, 0) }
+    }
+
+    const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
         // On Apple OS, dates before epoch are represented differently than on other
         // Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1`
         // and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and
@@ -100,9 +98,11 @@
             } else {
                 (tv_sec, tv_nsec)
             };
-        assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64);
-        // SAFETY: The assert above checks tv_nsec is within the valid range
-        Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
+        if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 {
+            Ok(unsafe { Self::new_unchecked(tv_sec, tv_nsec) })
+        } else {
+            Err(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid timestamp"))
+        }
     }
 
     pub fn now(clock: libc::clockid_t) -> Timespec {
@@ -126,13 +126,15 @@
             if let Some(clock_gettime64) = __clock_gettime64.get() {
                 let mut t = MaybeUninit::uninit();
                 cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
-                return Timespec::from(unsafe { t.assume_init() });
+                let t = unsafe { t.assume_init() };
+                return Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap();
             }
         }
 
         let mut t = MaybeUninit::uninit();
         cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
-        Timespec::from(unsafe { t.assume_init() })
+        let t = unsafe { t.assume_init() };
+        Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap()
     }
 
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
@@ -178,7 +180,7 @@
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(Timespec::new(secs, nsec.into()))
+        Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
@@ -190,7 +192,7 @@
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(Timespec::new(secs, nsec.into()))
+        Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
     }
 
     #[allow(dead_code)]
@@ -226,12 +228,6 @@
     }
 }
 
-impl From<libc::timespec> for Timespec {
-    fn from(t: libc::timespec) -> Timespec {
-        Timespec::new(t.tv_sec as i64, t.tv_nsec as i64)
-    }
-}
-
 #[cfg(all(
     target_os = "linux",
     target_env = "gnu",
@@ -260,18 +256,6 @@
     }
 }
 
-#[cfg(all(
-    target_os = "linux",
-    target_env = "gnu",
-    target_pointer_width = "32",
-    not(target_arch = "riscv32")
-))]
-impl From<__timespec64> for Timespec {
-    fn from(t: __timespec64) -> Timespec {
-        Timespec::new(t.tv_sec, t.tv_nsec.into())
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Instant {
     t: Timespec,
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index baaa825..d180122 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -1,4 +1,4 @@
-// Bindings generated by `windows-bindgen` 0.52.0
+// Bindings generated by `windows-bindgen` 0.55.0
 
 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
 #[link(name = "advapi32")]
@@ -12,16 +12,15 @@
 #[link(name = "advapi32")]
 extern "system" {
     #[link_name = "SystemFunction036"]
-    pub fn RtlGenRandom(randombuffer: *mut ::core::ffi::c_void, randombufferlength: u32)
-    -> BOOLEAN;
+    pub fn RtlGenRandom(randombuffer: *mut core::ffi::c_void, randombufferlength: u32) -> BOOLEAN;
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
+    pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK);
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK) -> ();
+    pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK);
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -47,7 +46,7 @@
         lpexistingfilename: PCWSTR,
         lpnewfilename: PCWSTR,
         lpprogressroutine: LPPROGRESS_ROUTINE,
-        lpdata: *const ::core::ffi::c_void,
+        lpdata: *const core::ffi::c_void,
         pbcancel: *mut BOOL,
         dwcopyflags: u32,
     ) -> BOOL;
@@ -110,7 +109,7 @@
         lpthreadattributes: *const SECURITY_ATTRIBUTES,
         binherithandles: BOOL,
         dwcreationflags: PROCESS_CREATION_FLAGS,
-        lpenvironment: *const ::core::ffi::c_void,
+        lpenvironment: *const core::ffi::c_void,
         lpcurrentdirectory: PCWSTR,
         lpstartupinfo: *const STARTUPINFOW,
         lpprocessinformation: *mut PROCESS_INFORMATION,
@@ -130,7 +129,7 @@
         lpthreadattributes: *const SECURITY_ATTRIBUTES,
         dwstacksize: usize,
         lpstartaddress: LPTHREAD_START_ROUTINE,
-        lpparameter: *const ::core::ffi::c_void,
+        lpparameter: *const core::ffi::c_void,
         dwcreationflags: THREAD_CREATION_FLAGS,
         lpthreadid: *mut u32,
     ) -> HANDLE;
@@ -150,16 +149,16 @@
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST) -> ();
+    pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST);
 }
 #[link(name = "kernel32")]
 extern "system" {
     pub fn DeviceIoControl(
         hdevice: HANDLE,
         dwiocontrolcode: u32,
-        lpinbuffer: *const ::core::ffi::c_void,
+        lpinbuffer: *const core::ffi::c_void,
         ninbuffersize: u32,
-        lpoutbuffer: *mut ::core::ffi::c_void,
+        lpoutbuffer: *mut core::ffi::c_void,
         noutbuffersize: u32,
         lpbytesreturned: *mut u32,
         lpoverlapped: *mut OVERLAPPED,
@@ -201,7 +200,7 @@
 extern "system" {
     pub fn FormatMessageW(
         dwflags: FORMAT_MESSAGE_OPTIONS,
-        lpsource: *const ::core::ffi::c_void,
+        lpsource: *const core::ffi::c_void,
         dwmessageid: u32,
         dwlanguageid: u32,
         lpbuffer: PWSTR,
@@ -269,7 +268,7 @@
     pub fn GetFileInformationByHandleEx(
         hfile: HANDLE,
         fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
-        lpfileinformation: *mut ::core::ffi::c_void,
+        lpfileinformation: *mut core::ffi::c_void,
         dwbuffersize: u32,
     ) -> BOOL;
 }
@@ -338,11 +337,11 @@
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn GetSystemInfo(lpsysteminfo: *mut SYSTEM_INFO) -> ();
+    pub fn GetSystemInfo(lpsysteminfo: *mut SYSTEM_INFO);
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> ();
+    pub fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime: *mut FILETIME);
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -362,7 +361,7 @@
         lpinitonce: *mut INIT_ONCE,
         dwflags: u32,
         fpending: *mut BOOL,
-        lpcontext: *mut *mut ::core::ffi::c_void,
+        lpcontext: *mut *mut core::ffi::c_void,
     ) -> BOOL;
 }
 #[link(name = "kernel32")]
@@ -370,7 +369,7 @@
     pub fn InitOnceComplete(
         lpinitonce: *mut INIT_ONCE,
         dwflags: u32,
-        lpcontext: *const ::core::ffi::c_void,
+        lpcontext: *const core::ffi::c_void,
     ) -> BOOL;
 }
 #[link(name = "kernel32")]
@@ -417,7 +416,7 @@
 extern "system" {
     pub fn ReadConsoleW(
         hconsoleinput: HANDLE,
-        lpbuffer: *mut ::core::ffi::c_void,
+        lpbuffer: *mut core::ffi::c_void,
         nnumberofcharstoread: u32,
         lpnumberofcharsread: *mut u32,
         pinputcontrol: *const CONSOLE_READCONSOLE_CONTROL,
@@ -445,11 +444,11 @@
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
+    pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK);
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK) -> ();
+    pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK);
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -475,7 +474,7 @@
     pub fn SetFileInformationByHandle(
         hfile: HANDLE,
         fileinformationclass: FILE_INFO_BY_HANDLE_CLASS,
-        lpfileinformation: *const ::core::ffi::c_void,
+        lpfileinformation: *const core::ffi::c_void,
         dwbuffersize: u32,
     ) -> BOOL;
 }
@@ -503,7 +502,7 @@
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn SetLastError(dwerrcode: WIN32_ERROR) -> ();
+    pub fn SetLastError(dwerrcode: WIN32_ERROR);
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -516,13 +515,13 @@
         lpduetime: *const i64,
         lperiod: i32,
         pfncompletionroutine: PTIMERAPCROUTINE,
-        lpargtocompletionroutine: *const ::core::ffi::c_void,
+        lpargtocompletionroutine: *const core::ffi::c_void,
         fresume: BOOL,
     ) -> BOOL;
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn Sleep(dwmilliseconds: u32) -> ();
+    pub fn Sleep(dwmilliseconds: u32);
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -555,11 +554,11 @@
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn TlsGetValue(dwtlsindex: u32) -> *mut ::core::ffi::c_void;
+    pub fn TlsGetValue(dwtlsindex: u32) -> *mut core::ffi::c_void;
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn TlsSetValue(dwtlsindex: u32, lptlsvalue: *const ::core::ffi::c_void) -> BOOL;
+    pub fn TlsSetValue(dwtlsindex: u32, lptlsvalue: *const core::ffi::c_void) -> BOOL;
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -575,9 +574,9 @@
         lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
         dwflags: u32,
         attribute: usize,
-        lpvalue: *const ::core::ffi::c_void,
+        lpvalue: *const core::ffi::c_void,
         cbsize: usize,
-        lppreviousvalue: *mut ::core::ffi::c_void,
+        lppreviousvalue: *mut core::ffi::c_void,
         lpreturnsize: *const usize,
     ) -> BOOL;
 }
@@ -596,11 +595,11 @@
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> ();
+    pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE);
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> ();
+    pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE);
 }
 #[link(name = "kernel32")]
 extern "system" {
@@ -619,10 +618,10 @@
 extern "system" {
     pub fn WriteConsoleW(
         hconsoleoutput: HANDLE,
-        lpbuffer: *const ::core::ffi::c_void,
+        lpbuffer: *const core::ffi::c_void,
         nnumberofcharstowrite: u32,
         lpnumberofcharswritten: *mut u32,
-        lpreserved: *const ::core::ffi::c_void,
+        lpreserved: *const core::ffi::c_void,
     ) -> BOOL;
 }
 #[link(name = "kernel32")]
@@ -647,7 +646,7 @@
         shareaccess: FILE_SHARE_MODE,
         createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
         createoptions: NTCREATEFILE_CREATE_OPTIONS,
-        eabuffer: *const ::core::ffi::c_void,
+        eabuffer: *const core::ffi::c_void,
         ealength: u32,
     ) -> NTSTATUS;
 }
@@ -657,9 +656,9 @@
         filehandle: HANDLE,
         event: HANDLE,
         apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const ::core::ffi::c_void,
+        apccontext: *const core::ffi::c_void,
         iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *mut ::core::ffi::c_void,
+        buffer: *mut core::ffi::c_void,
         length: u32,
         byteoffset: *const i64,
         key: *const u32,
@@ -671,9 +670,9 @@
         filehandle: HANDLE,
         event: HANDLE,
         apcroutine: PIO_APC_ROUTINE,
-        apccontext: *const ::core::ffi::c_void,
+        apccontext: *const core::ffi::c_void,
         iostatusblock: *mut IO_STATUS_BLOCK,
-        buffer: *const ::core::ffi::c_void,
+        buffer: *const core::ffi::c_void,
         length: u32,
         byteoffset: *const i64,
         key: *const u32,
@@ -760,7 +759,7 @@
 }
 #[link(name = "ws2_32")]
 extern "system" {
-    pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA) -> ();
+    pub fn freeaddrinfo(paddrinfo: *const ADDRINFOA);
 }
 #[link(name = "ws2_32")]
 extern "system" {
@@ -852,8 +851,8 @@
     pub ai_addr: *mut SOCKADDR,
     pub ai_next: *mut ADDRINFOA,
 }
-impl ::core::marker::Copy for ADDRINFOA {}
-impl ::core::clone::Clone for ADDRINFOA {
+impl Copy for ADDRINFOA {}
+impl Clone for ADDRINFOA {
     fn clone(&self) -> Self {
         *self
     }
@@ -871,8 +870,8 @@
     pub H: [u16; 8],
     pub B: [u8; 16],
 }
-impl ::core::marker::Copy for ARM64_NT_NEON128 {}
-impl ::core::clone::Clone for ARM64_NT_NEON128 {
+impl Copy for ARM64_NT_NEON128 {}
+impl Clone for ARM64_NT_NEON128 {
     fn clone(&self) -> Self {
         *self
     }
@@ -882,8 +881,8 @@
     pub Low: u64,
     pub High: i64,
 }
-impl ::core::marker::Copy for ARM64_NT_NEON128_0 {}
-impl ::core::clone::Clone for ARM64_NT_NEON128_0 {
+impl Copy for ARM64_NT_NEON128_0 {}
+impl Clone for ARM64_NT_NEON128_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -904,8 +903,8 @@
     pub nFileIndexHigh: u32,
     pub nFileIndexLow: u32,
 }
-impl ::core::marker::Copy for BY_HANDLE_FILE_INFORMATION {}
-impl ::core::clone::Clone for BY_HANDLE_FILE_INFORMATION {
+impl Copy for BY_HANDLE_FILE_INFORMATION {}
+impl Clone for BY_HANDLE_FILE_INFORMATION {
     fn clone(&self) -> Self {
         *self
     }
@@ -915,10 +914,10 @@
 pub type COMPARESTRING_RESULT = i32;
 #[repr(C)]
 pub struct CONDITION_VARIABLE {
-    pub Ptr: *mut ::core::ffi::c_void,
+    pub Ptr: *mut core::ffi::c_void,
 }
-impl ::core::marker::Copy for CONDITION_VARIABLE {}
-impl ::core::clone::Clone for CONDITION_VARIABLE {
+impl Copy for CONDITION_VARIABLE {}
+impl Clone for CONDITION_VARIABLE {
     fn clone(&self) -> Self {
         *self
     }
@@ -931,8 +930,8 @@
     pub dwCtrlWakeupMask: u32,
     pub dwControlKeyState: u32,
 }
-impl ::core::marker::Copy for CONSOLE_READCONSOLE_CONTROL {}
-impl ::core::clone::Clone for CONSOLE_READCONSOLE_CONTROL {
+impl Copy for CONSOLE_READCONSOLE_CONTROL {}
+impl Clone for CONSOLE_READCONSOLE_CONTROL {
     fn clone(&self) -> Self {
         *self
     }
@@ -954,9 +953,9 @@
     pub Wvr: [u64; 2],
 }
 #[cfg(target_arch = "aarch64")]
-impl ::core::marker::Copy for CONTEXT {}
+impl Copy for CONTEXT {}
 #[cfg(target_arch = "aarch64")]
-impl ::core::clone::Clone for CONTEXT {
+impl Clone for CONTEXT {
     fn clone(&self) -> Self {
         *self
     }
@@ -968,9 +967,9 @@
     pub X: [u64; 31],
 }
 #[cfg(target_arch = "aarch64")]
-impl ::core::marker::Copy for CONTEXT_0 {}
+impl Copy for CONTEXT_0 {}
 #[cfg(target_arch = "aarch64")]
-impl ::core::clone::Clone for CONTEXT_0 {
+impl Clone for CONTEXT_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -1011,9 +1010,9 @@
     pub Lr: u64,
 }
 #[cfg(target_arch = "aarch64")]
-impl ::core::marker::Copy for CONTEXT_0_0 {}
+impl Copy for CONTEXT_0_0 {}
 #[cfg(target_arch = "aarch64")]
-impl ::core::clone::Clone for CONTEXT_0_0 {
+impl Clone for CONTEXT_0_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -1069,9 +1068,9 @@
     pub LastExceptionFromRip: u64,
 }
 #[cfg(target_arch = "x86_64")]
-impl ::core::marker::Copy for CONTEXT {}
+impl Copy for CONTEXT {}
 #[cfg(target_arch = "x86_64")]
-impl ::core::clone::Clone for CONTEXT {
+impl Clone for CONTEXT {
     fn clone(&self) -> Self {
         *self
     }
@@ -1083,9 +1082,9 @@
     pub Anonymous: CONTEXT_0_0,
 }
 #[cfg(target_arch = "x86_64")]
-impl ::core::marker::Copy for CONTEXT_0 {}
+impl Copy for CONTEXT_0 {}
 #[cfg(target_arch = "x86_64")]
-impl ::core::clone::Clone for CONTEXT_0 {
+impl Clone for CONTEXT_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -1113,9 +1112,9 @@
     pub Xmm15: M128A,
 }
 #[cfg(target_arch = "x86_64")]
-impl ::core::marker::Copy for CONTEXT_0_0 {}
+impl Copy for CONTEXT_0_0 {}
 #[cfg(target_arch = "x86_64")]
-impl ::core::clone::Clone for CONTEXT_0_0 {
+impl Clone for CONTEXT_0_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -1150,9 +1149,9 @@
     pub ExtendedRegisters: [u8; 512],
 }
 #[cfg(target_arch = "x86")]
-impl ::core::marker::Copy for CONTEXT {}
+impl Copy for CONTEXT {}
 #[cfg(target_arch = "x86")]
-impl ::core::clone::Clone for CONTEXT {
+impl Clone for CONTEXT {
     fn clone(&self) -> Self {
         *self
     }
@@ -3073,19 +3072,19 @@
     pub ExceptionCode: NTSTATUS,
     pub ExceptionFlags: u32,
     pub ExceptionRecord: *mut EXCEPTION_RECORD,
-    pub ExceptionAddress: *mut ::core::ffi::c_void,
+    pub ExceptionAddress: *mut core::ffi::c_void,
     pub NumberParameters: u32,
     pub ExceptionInformation: [usize; 15],
 }
-impl ::core::marker::Copy for EXCEPTION_RECORD {}
-impl ::core::clone::Clone for EXCEPTION_RECORD {
+impl Copy for EXCEPTION_RECORD {}
+impl Clone for EXCEPTION_RECORD {
     fn clone(&self) -> Self {
         *self
     }
 }
-pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = -1073741571i32;
+pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _;
 pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32;
-pub const E_NOTIMPL: HRESULT = -2147467263i32;
+pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _;
 pub const ExceptionCollidedUnwind: EXCEPTION_DISPOSITION = 3i32;
 pub const ExceptionContinueExecution: EXCEPTION_DISPOSITION = 0i32;
 pub const ExceptionContinueSearch: EXCEPTION_DISPOSITION = 1i32;
@@ -3093,15 +3092,15 @@
 pub type FACILITY_CODE = u32;
 pub const FACILITY_NT_BIT: FACILITY_CODE = 268435456u32;
 pub const FALSE: BOOL = 0i32;
-pub type FARPROC = ::core::option::Option<unsafe extern "system" fn() -> isize>;
+pub type FARPROC = Option<unsafe extern "system" fn() -> isize>;
 pub const FAST_FAIL_FATAL_APP_EXIT: u32 = 7u32;
 #[repr(C)]
 pub struct FD_SET {
     pub fd_count: u32,
     pub fd_array: [SOCKET; 64],
 }
-impl ::core::marker::Copy for FD_SET {}
-impl ::core::clone::Clone for FD_SET {
+impl Copy for FD_SET {}
+impl Clone for FD_SET {
     fn clone(&self) -> Self {
         *self
     }
@@ -3111,8 +3110,8 @@
     pub dwLowDateTime: u32,
     pub dwHighDateTime: u32,
 }
-impl ::core::marker::Copy for FILETIME {}
-impl ::core::clone::Clone for FILETIME {
+impl Copy for FILETIME {}
+impl Clone for FILETIME {
     fn clone(&self) -> Self {
         *self
     }
@@ -3124,8 +3123,8 @@
 pub struct FILE_ALLOCATION_INFO {
     pub AllocationSize: i64,
 }
-impl ::core::marker::Copy for FILE_ALLOCATION_INFO {}
-impl ::core::clone::Clone for FILE_ALLOCATION_INFO {
+impl Copy for FILE_ALLOCATION_INFO {}
+impl Clone for FILE_ALLOCATION_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3156,8 +3155,8 @@
     pub FileAttributes: u32,
     pub ReparseTag: u32,
 }
-impl ::core::marker::Copy for FILE_ATTRIBUTE_TAG_INFO {}
-impl ::core::clone::Clone for FILE_ATTRIBUTE_TAG_INFO {
+impl Copy for FILE_ATTRIBUTE_TAG_INFO {}
+impl Clone for FILE_ATTRIBUTE_TAG_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3173,8 +3172,8 @@
     pub ChangeTime: i64,
     pub FileAttributes: u32,
 }
-impl ::core::marker::Copy for FILE_BASIC_INFO {}
-impl ::core::clone::Clone for FILE_BASIC_INFO {
+impl Copy for FILE_BASIC_INFO {}
+impl Clone for FILE_BASIC_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3201,8 +3200,8 @@
 pub struct FILE_DISPOSITION_INFO {
     pub DeleteFile: BOOLEAN,
 }
-impl ::core::marker::Copy for FILE_DISPOSITION_INFO {}
-impl ::core::clone::Clone for FILE_DISPOSITION_INFO {
+impl Copy for FILE_DISPOSITION_INFO {}
+impl Clone for FILE_DISPOSITION_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3211,8 +3210,8 @@
 pub struct FILE_DISPOSITION_INFO_EX {
     pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS,
 }
-impl ::core::marker::Copy for FILE_DISPOSITION_INFO_EX {}
-impl ::core::clone::Clone for FILE_DISPOSITION_INFO_EX {
+impl Copy for FILE_DISPOSITION_INFO_EX {}
+impl Clone for FILE_DISPOSITION_INFO_EX {
     fn clone(&self) -> Self {
         *self
     }
@@ -3223,8 +3222,8 @@
 pub struct FILE_END_OF_FILE_INFO {
     pub EndOfFile: i64,
 }
-impl ::core::marker::Copy for FILE_END_OF_FILE_INFO {}
-impl ::core::clone::Clone for FILE_END_OF_FILE_INFO {
+impl Copy for FILE_END_OF_FILE_INFO {}
+impl Clone for FILE_END_OF_FILE_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3264,8 +3263,8 @@
     pub FileId: i64,
     pub FileName: [u16; 1],
 }
-impl ::core::marker::Copy for FILE_ID_BOTH_DIR_INFO {}
-impl ::core::clone::Clone for FILE_ID_BOTH_DIR_INFO {
+impl Copy for FILE_ID_BOTH_DIR_INFO {}
+impl Clone for FILE_ID_BOTH_DIR_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3275,8 +3274,8 @@
 pub struct FILE_IO_PRIORITY_HINT_INFO {
     pub PriorityHint: PRIORITY_HINT,
 }
-impl ::core::marker::Copy for FILE_IO_PRIORITY_HINT_INFO {}
-impl ::core::clone::Clone for FILE_IO_PRIORITY_HINT_INFO {
+impl Copy for FILE_IO_PRIORITY_HINT_INFO {}
+impl Clone for FILE_IO_PRIORITY_HINT_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3318,8 +3317,8 @@
     pub DeletePending: BOOLEAN,
     pub Directory: BOOLEAN,
 }
-impl ::core::marker::Copy for FILE_STANDARD_INFO {}
-impl ::core::clone::Clone for FILE_STANDARD_INFO {
+impl Copy for FILE_STANDARD_INFO {}
+impl Clone for FILE_STANDARD_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3353,9 +3352,9 @@
     pub Cr0NpxState: u32,
 }
 #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
-impl ::core::marker::Copy for FLOATING_SAVE_AREA {}
+impl Copy for FLOATING_SAVE_AREA {}
 #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
-impl ::core::clone::Clone for FLOATING_SAVE_AREA {
+impl Clone for FLOATING_SAVE_AREA {
     fn clone(&self) -> Self {
         *self
     }
@@ -3374,9 +3373,9 @@
     pub Spare0: u32,
 }
 #[cfg(target_arch = "x86")]
-impl ::core::marker::Copy for FLOATING_SAVE_AREA {}
+impl Copy for FLOATING_SAVE_AREA {}
 #[cfg(target_arch = "x86")]
-impl ::core::clone::Clone for FLOATING_SAVE_AREA {
+impl Clone for FLOATING_SAVE_AREA {
     fn clone(&self) -> Self {
         *self
     }
@@ -3429,8 +3428,8 @@
     pub data3: u16,
     pub data4: [u8; 8],
 }
-impl ::core::marker::Copy for GUID {}
-impl ::core::clone::Clone for GUID {
+impl Copy for GUID {}
+impl Clone for GUID {
     fn clone(&self) -> Self {
         *self
     }
@@ -3445,21 +3444,21 @@
         }
     }
 }
-pub type HANDLE = *mut ::core::ffi::c_void;
+pub type HANDLE = *mut core::ffi::c_void;
 pub type HANDLE_FLAGS = u32;
 pub const HANDLE_FLAG_INHERIT: HANDLE_FLAGS = 1u32;
 pub const HANDLE_FLAG_PROTECT_FROM_CLOSE: HANDLE_FLAGS = 2u32;
 pub const HIGH_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 128u32;
-pub type HLOCAL = *mut ::core::ffi::c_void;
-pub type HMODULE = *mut ::core::ffi::c_void;
+pub type HLOCAL = *mut core::ffi::c_void;
+pub type HMODULE = *mut core::ffi::c_void;
 pub type HRESULT = i32;
 pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32;
 #[repr(C)]
 pub struct IN6_ADDR {
     pub u: IN6_ADDR_0,
 }
-impl ::core::marker::Copy for IN6_ADDR {}
-impl ::core::clone::Clone for IN6_ADDR {
+impl Copy for IN6_ADDR {}
+impl Clone for IN6_ADDR {
     fn clone(&self) -> Self {
         *self
     }
@@ -3469,8 +3468,8 @@
     pub Byte: [u8; 16],
     pub Word: [u16; 8],
 }
-impl ::core::marker::Copy for IN6_ADDR_0 {}
-impl ::core::clone::Clone for IN6_ADDR_0 {
+impl Copy for IN6_ADDR_0 {}
+impl Clone for IN6_ADDR_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -3480,10 +3479,10 @@
 pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32;
 #[repr(C)]
 pub union INIT_ONCE {
-    pub Ptr: *mut ::core::ffi::c_void,
+    pub Ptr: *mut core::ffi::c_void,
 }
-impl ::core::marker::Copy for INIT_ONCE {}
-impl ::core::clone::Clone for INIT_ONCE {
+impl Copy for INIT_ONCE {}
+impl Clone for INIT_ONCE {
     fn clone(&self) -> Self {
         *self
     }
@@ -3495,8 +3494,8 @@
 pub struct IN_ADDR {
     pub S_un: IN_ADDR_0,
 }
-impl ::core::marker::Copy for IN_ADDR {}
-impl ::core::clone::Clone for IN_ADDR {
+impl Copy for IN_ADDR {}
+impl Clone for IN_ADDR {
     fn clone(&self) -> Self {
         *self
     }
@@ -3507,8 +3506,8 @@
     pub S_un_w: IN_ADDR_0_1,
     pub S_addr: u32,
 }
-impl ::core::marker::Copy for IN_ADDR_0 {}
-impl ::core::clone::Clone for IN_ADDR_0 {
+impl Copy for IN_ADDR_0 {}
+impl Clone for IN_ADDR_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -3520,8 +3519,8 @@
     pub s_b3: u8,
     pub s_b4: u8,
 }
-impl ::core::marker::Copy for IN_ADDR_0_0 {}
-impl ::core::clone::Clone for IN_ADDR_0_0 {
+impl Copy for IN_ADDR_0_0 {}
+impl Clone for IN_ADDR_0_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -3531,8 +3530,8 @@
     pub s_w1: u16,
     pub s_w2: u16,
 }
-impl ::core::marker::Copy for IN_ADDR_0_1 {}
-impl ::core::clone::Clone for IN_ADDR_0_1 {
+impl Copy for IN_ADDR_0_1 {}
+impl Clone for IN_ADDR_0_1 {
     fn clone(&self) -> Self {
         *self
     }
@@ -3544,8 +3543,8 @@
     pub Anonymous: IO_STATUS_BLOCK_0,
     pub Information: usize,
 }
-impl ::core::marker::Copy for IO_STATUS_BLOCK {}
-impl ::core::clone::Clone for IO_STATUS_BLOCK {
+impl Copy for IO_STATUS_BLOCK {}
+impl Clone for IO_STATUS_BLOCK {
     fn clone(&self) -> Self {
         *self
     }
@@ -3553,10 +3552,10 @@
 #[repr(C)]
 pub union IO_STATUS_BLOCK_0 {
     pub Status: NTSTATUS,
-    pub Pointer: *mut ::core::ffi::c_void,
+    pub Pointer: *mut core::ffi::c_void,
 }
-impl ::core::marker::Copy for IO_STATUS_BLOCK_0 {}
-impl ::core::clone::Clone for IO_STATUS_BLOCK_0 {
+impl Copy for IO_STATUS_BLOCK_0 {}
+impl Clone for IO_STATUS_BLOCK_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -3606,8 +3605,8 @@
     pub ipv6mr_multiaddr: IN6_ADDR,
     pub ipv6mr_interface: u32,
 }
-impl ::core::marker::Copy for IPV6_MREQ {}
-impl ::core::clone::Clone for IPV6_MREQ {
+impl Copy for IPV6_MREQ {}
+impl Clone for IPV6_MREQ {
     fn clone(&self) -> Self {
         *self
     }
@@ -3621,8 +3620,8 @@
     pub imr_multiaddr: IN_ADDR,
     pub imr_interface: IN_ADDR,
 }
-impl ::core::marker::Copy for IP_MREQ {}
-impl ::core::clone::Clone for IP_MREQ {
+impl Copy for IP_MREQ {}
+impl Clone for IP_MREQ {
     fn clone(&self) -> Self {
         *self
     }
@@ -3635,21 +3634,21 @@
     pub l_onoff: u16,
     pub l_linger: u16,
 }
-impl ::core::marker::Copy for LINGER {}
-impl ::core::clone::Clone for LINGER {
+impl Copy for LINGER {}
+impl Clone for LINGER {
     fn clone(&self) -> Self {
         *self
     }
 }
-pub type LPOVERLAPPED_COMPLETION_ROUTINE = ::core::option::Option<
+pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option<
     unsafe extern "system" fn(
         dwerrorcode: u32,
         dwnumberofbytestransfered: u32,
         lpoverlapped: *mut OVERLAPPED,
-    ) -> (),
+    ),
 >;
-pub type LPPROC_THREAD_ATTRIBUTE_LIST = *mut ::core::ffi::c_void;
-pub type LPPROGRESS_ROUTINE = ::core::option::Option<
+pub type LPPROC_THREAD_ATTRIBUTE_LIST = *mut core::ffi::c_void;
+pub type LPPROGRESS_ROUTINE = Option<
     unsafe extern "system" fn(
         totalfilesize: i64,
         totalbytestransferred: i64,
@@ -3659,28 +3658,27 @@
         dwcallbackreason: LPPROGRESS_ROUTINE_CALLBACK_REASON,
         hsourcefile: HANDLE,
         hdestinationfile: HANDLE,
-        lpdata: *const ::core::ffi::c_void,
+        lpdata: *const core::ffi::c_void,
     ) -> u32,
 >;
 pub type LPPROGRESS_ROUTINE_CALLBACK_REASON = u32;
-pub type LPTHREAD_START_ROUTINE = ::core::option::Option<
-    unsafe extern "system" fn(lpthreadparameter: *mut ::core::ffi::c_void) -> u32,
->;
-pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = ::core::option::Option<
+pub type LPTHREAD_START_ROUTINE =
+    Option<unsafe extern "system" fn(lpthreadparameter: *mut core::ffi::c_void) -> u32>;
+pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = Option<
     unsafe extern "system" fn(
         dwerror: u32,
         cbtransferred: u32,
         lpoverlapped: *mut OVERLAPPED,
         dwflags: u32,
-    ) -> (),
+    ),
 >;
 #[repr(C)]
 pub struct M128A {
     pub Low: u64,
     pub High: i64,
 }
-impl ::core::marker::Copy for M128A {}
-impl ::core::clone::Clone for M128A {
+impl Copy for M128A {}
+impl Clone for M128A {
     fn clone(&self) -> Self {
         *self
     }
@@ -3717,11 +3715,11 @@
     pub RootDirectory: HANDLE,
     pub ObjectName: *const UNICODE_STRING,
     pub Attributes: u32,
-    pub SecurityDescriptor: *const ::core::ffi::c_void,
-    pub SecurityQualityOfService: *const ::core::ffi::c_void,
+    pub SecurityDescriptor: *const core::ffi::c_void,
+    pub SecurityQualityOfService: *const core::ffi::c_void,
 }
-impl ::core::marker::Copy for OBJECT_ATTRIBUTES {}
-impl ::core::clone::Clone for OBJECT_ATTRIBUTES {
+impl Copy for OBJECT_ATTRIBUTES {}
+impl Clone for OBJECT_ATTRIBUTES {
     fn clone(&self) -> Self {
         *self
     }
@@ -3736,8 +3734,8 @@
     pub Anonymous: OVERLAPPED_0,
     pub hEvent: HANDLE,
 }
-impl ::core::marker::Copy for OVERLAPPED {}
-impl ::core::clone::Clone for OVERLAPPED {
+impl Copy for OVERLAPPED {}
+impl Clone for OVERLAPPED {
     fn clone(&self) -> Self {
         *self
     }
@@ -3745,10 +3743,10 @@
 #[repr(C)]
 pub union OVERLAPPED_0 {
     pub Anonymous: OVERLAPPED_0_0,
-    pub Pointer: *mut ::core::ffi::c_void,
+    pub Pointer: *mut core::ffi::c_void,
 }
-impl ::core::marker::Copy for OVERLAPPED_0 {}
-impl ::core::clone::Clone for OVERLAPPED_0 {
+impl Copy for OVERLAPPED_0 {}
+impl Clone for OVERLAPPED_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -3758,20 +3756,20 @@
     pub Offset: u32,
     pub OffsetHigh: u32,
 }
-impl ::core::marker::Copy for OVERLAPPED_0_0 {}
-impl ::core::clone::Clone for OVERLAPPED_0_0 {
+impl Copy for OVERLAPPED_0_0 {}
+impl Clone for OVERLAPPED_0_0 {
     fn clone(&self) -> Self {
         *self
     }
 }
 pub type PCSTR = *const u8;
 pub type PCWSTR = *const u16;
-pub type PIO_APC_ROUTINE = ::core::option::Option<
+pub type PIO_APC_ROUTINE = Option<
     unsafe extern "system" fn(
-        apccontext: *mut ::core::ffi::c_void,
+        apccontext: *mut core::ffi::c_void,
         iostatusblock: *mut IO_STATUS_BLOCK,
         reserved: u32,
-    ) -> (),
+    ),
 >;
 pub const PIPE_ACCEPT_REMOTE_CLIENTS: NAMED_PIPE_MODE = 0u32;
 pub const PIPE_ACCESS_DUPLEX: FILE_FLAGS_AND_ATTRIBUTES = 3u32;
@@ -3796,8 +3794,8 @@
     pub dwProcessId: u32,
     pub dwThreadId: u32,
 }
-impl ::core::marker::Copy for PROCESS_INFORMATION {}
-impl ::core::clone::Clone for PROCESS_INFORMATION {
+impl Copy for PROCESS_INFORMATION {}
+impl Clone for PROCESS_INFORMATION {
     fn clone(&self) -> Self {
         *self
     }
@@ -3809,12 +3807,12 @@
 pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
 pub const PROGRESS_CONTINUE: u32 = 0u32;
 pub type PSTR = *mut u8;
-pub type PTIMERAPCROUTINE = ::core::option::Option<
+pub type PTIMERAPCROUTINE = Option<
     unsafe extern "system" fn(
-        lpargtocompletionroutine: *const ::core::ffi::c_void,
+        lpargtocompletionroutine: *const core::ffi::c_void,
         dwtimerlowvalue: u32,
         dwtimerhighvalue: u32,
-    ) -> (),
+    ),
 >;
 pub type PWSTR = *mut u16;
 pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
@@ -3826,11 +3824,11 @@
 #[repr(C)]
 pub struct SECURITY_ATTRIBUTES {
     pub nLength: u32,
-    pub lpSecurityDescriptor: *mut ::core::ffi::c_void,
+    pub lpSecurityDescriptor: *mut core::ffi::c_void,
     pub bInheritHandle: BOOL,
 }
-impl ::core::marker::Copy for SECURITY_ATTRIBUTES {}
-impl ::core::clone::Clone for SECURITY_ATTRIBUTES {
+impl Copy for SECURITY_ATTRIBUTES {}
+impl Clone for SECURITY_ATTRIBUTES {
     fn clone(&self) -> Self {
         *self
     }
@@ -3847,10 +3845,10 @@
 #[repr(C)]
 pub struct SOCKADDR {
     pub sa_family: ADDRESS_FAMILY,
-    pub sa_data: [u8; 14],
+    pub sa_data: [i8; 14],
 }
-impl ::core::marker::Copy for SOCKADDR {}
-impl ::core::clone::Clone for SOCKADDR {
+impl Copy for SOCKADDR {}
+impl Clone for SOCKADDR {
     fn clone(&self) -> Self {
         *self
     }
@@ -3858,10 +3856,10 @@
 #[repr(C)]
 pub struct SOCKADDR_UN {
     pub sun_family: ADDRESS_FAMILY,
-    pub sun_path: [u8; 108],
+    pub sun_path: [i8; 108],
 }
-impl ::core::marker::Copy for SOCKADDR_UN {}
-impl ::core::clone::Clone for SOCKADDR_UN {
+impl Copy for SOCKADDR_UN {}
+impl Clone for SOCKADDR_UN {
     fn clone(&self) -> Self {
         *self
     }
@@ -3882,10 +3880,10 @@
 pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32;
 #[repr(C)]
 pub struct SRWLOCK {
-    pub Ptr: *mut ::core::ffi::c_void,
+    pub Ptr: *mut core::ffi::c_void,
 }
-impl ::core::marker::Copy for SRWLOCK {}
-impl ::core::clone::Clone for SRWLOCK {
+impl Copy for SRWLOCK {}
+impl Clone for SRWLOCK {
     fn clone(&self) -> Self {
         *self
     }
@@ -3915,8 +3913,8 @@
     pub StartupInfo: STARTUPINFOW,
     pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST,
 }
-impl ::core::marker::Copy for STARTUPINFOEXW {}
-impl ::core::clone::Clone for STARTUPINFOEXW {
+impl Copy for STARTUPINFOEXW {}
+impl Clone for STARTUPINFOEXW {
     fn clone(&self) -> Self {
         *self
     }
@@ -3942,19 +3940,19 @@
     pub hStdOutput: HANDLE,
     pub hStdError: HANDLE,
 }
-impl ::core::marker::Copy for STARTUPINFOW {}
-impl ::core::clone::Clone for STARTUPINFOW {
+impl Copy for STARTUPINFOW {}
+impl Clone for STARTUPINFOW {
     fn clone(&self) -> Self {
         *self
     }
 }
 pub type STARTUPINFOW_FLAGS = u32;
-pub const STATUS_DELETE_PENDING: NTSTATUS = -1073741738i32;
-pub const STATUS_END_OF_FILE: NTSTATUS = -1073741807i32;
-pub const STATUS_INVALID_PARAMETER: NTSTATUS = -1073741811i32;
-pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = -1073741822i32;
-pub const STATUS_PENDING: NTSTATUS = 259i32;
-pub const STATUS_SUCCESS: NTSTATUS = 0i32;
+pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _;
+pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
+pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xC000000D_u32 as _;
+pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
+pub const STATUS_PENDING: NTSTATUS = 0x103_u32 as _;
+pub const STATUS_SUCCESS: NTSTATUS = 0x0_u32 as _;
 pub const STD_ERROR_HANDLE: STD_HANDLE = 4294967284u32;
 pub type STD_HANDLE = u32;
 pub const STD_INPUT_HANDLE: STD_HANDLE = 4294967286u32;
@@ -3969,8 +3967,8 @@
 pub struct SYSTEM_INFO {
     pub Anonymous: SYSTEM_INFO_0,
     pub dwPageSize: u32,
-    pub lpMinimumApplicationAddress: *mut ::core::ffi::c_void,
-    pub lpMaximumApplicationAddress: *mut ::core::ffi::c_void,
+    pub lpMinimumApplicationAddress: *mut core::ffi::c_void,
+    pub lpMaximumApplicationAddress: *mut core::ffi::c_void,
     pub dwActiveProcessorMask: usize,
     pub dwNumberOfProcessors: u32,
     pub dwProcessorType: u32,
@@ -3978,8 +3976,8 @@
     pub wProcessorLevel: u16,
     pub wProcessorRevision: u16,
 }
-impl ::core::marker::Copy for SYSTEM_INFO {}
-impl ::core::clone::Clone for SYSTEM_INFO {
+impl Copy for SYSTEM_INFO {}
+impl Clone for SYSTEM_INFO {
     fn clone(&self) -> Self {
         *self
     }
@@ -3989,8 +3987,8 @@
     pub dwOemId: u32,
     pub Anonymous: SYSTEM_INFO_0_0,
 }
-impl ::core::marker::Copy for SYSTEM_INFO_0 {}
-impl ::core::clone::Clone for SYSTEM_INFO_0 {
+impl Copy for SYSTEM_INFO_0 {}
+impl Clone for SYSTEM_INFO_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -4000,8 +3998,8 @@
     pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE,
     pub wReserved: u16,
 }
-impl ::core::marker::Copy for SYSTEM_INFO_0_0 {}
-impl ::core::clone::Clone for SYSTEM_INFO_0_0 {
+impl Copy for SYSTEM_INFO_0_0 {}
+impl Clone for SYSTEM_INFO_0_0 {
     fn clone(&self) -> Self {
         *self
     }
@@ -4017,8 +4015,8 @@
     pub tv_sec: i32,
     pub tv_usec: i32,
 }
-impl ::core::marker::Copy for TIMEVAL {}
-impl ::core::clone::Clone for TIMEVAL {
+impl Copy for TIMEVAL {}
+impl Clone for TIMEVAL {
     fn clone(&self) -> Self {
         *self
     }
@@ -4054,8 +4052,8 @@
     pub MaximumLength: u16,
     pub Buffer: PWSTR,
 }
-impl ::core::marker::Copy for UNICODE_STRING {}
-impl ::core::clone::Clone for UNICODE_STRING {
+impl Copy for UNICODE_STRING {}
+impl Clone for UNICODE_STRING {
     fn clone(&self) -> Self {
         *self
     }
@@ -4085,8 +4083,8 @@
     pub cFileName: [u16; 260],
     pub cAlternateFileName: [u16; 14],
 }
-impl ::core::marker::Copy for WIN32_FIND_DATAW {}
-impl ::core::clone::Clone for WIN32_FIND_DATAW {
+impl Copy for WIN32_FIND_DATAW {}
+impl Clone for WIN32_FIND_DATAW {
     fn clone(&self) -> Self {
         *self
     }
@@ -4101,8 +4099,8 @@
     pub len: u32,
     pub buf: PSTR,
 }
-impl ::core::marker::Copy for WSABUF {}
-impl ::core::clone::Clone for WSABUF {
+impl Copy for WSABUF {}
+impl Clone for WSABUF {
     fn clone(&self) -> Self {
         *self
     }
@@ -4115,13 +4113,13 @@
     pub iMaxSockets: u16,
     pub iMaxUdpDg: u16,
     pub lpVendorInfo: PSTR,
-    pub szDescription: [u8; 257],
-    pub szSystemStatus: [u8; 129],
+    pub szDescription: [i8; 257],
+    pub szSystemStatus: [i8; 129],
 }
 #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
-impl ::core::marker::Copy for WSADATA {}
+impl Copy for WSADATA {}
 #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
-impl ::core::clone::Clone for WSADATA {
+impl Clone for WSADATA {
     fn clone(&self) -> Self {
         *self
     }
@@ -4131,16 +4129,16 @@
 pub struct WSADATA {
     pub wVersion: u16,
     pub wHighVersion: u16,
-    pub szDescription: [u8; 257],
-    pub szSystemStatus: [u8; 129],
+    pub szDescription: [i8; 257],
+    pub szSystemStatus: [i8; 129],
     pub iMaxSockets: u16,
     pub iMaxUdpDg: u16,
     pub lpVendorInfo: PSTR,
 }
 #[cfg(target_arch = "x86")]
-impl ::core::marker::Copy for WSADATA {}
+impl Copy for WSADATA {}
 #[cfg(target_arch = "x86")]
-impl ::core::clone::Clone for WSADATA {
+impl Clone for WSADATA {
     fn clone(&self) -> Self {
         *self
     }
@@ -4204,8 +4202,8 @@
     pub ChainLen: i32,
     pub ChainEntries: [u32; 7],
 }
-impl ::core::marker::Copy for WSAPROTOCOLCHAIN {}
-impl ::core::clone::Clone for WSAPROTOCOLCHAIN {
+impl Copy for WSAPROTOCOLCHAIN {}
+impl Clone for WSAPROTOCOLCHAIN {
     fn clone(&self) -> Self {
         *self
     }
@@ -4233,8 +4231,8 @@
     pub dwProviderReserved: u32,
     pub szProtocol: [u16; 256],
 }
-impl ::core::marker::Copy for WSAPROTOCOL_INFOW {}
-impl ::core::clone::Clone for WSAPROTOCOL_INFOW {
+impl Copy for WSAPROTOCOL_INFOW {}
+impl Clone for WSAPROTOCOL_INFOW {
     fn clone(&self) -> Self {
         *self
     }
@@ -4308,9 +4306,9 @@
     pub Reserved4: [u8; 96],
 }
 #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
-impl ::core::marker::Copy for XSAVE_FORMAT {}
+impl Copy for XSAVE_FORMAT {}
 #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
-impl ::core::clone::Clone for XSAVE_FORMAT {
+impl Clone for XSAVE_FORMAT {
     fn clone(&self) -> Self {
         *self
     }
@@ -4336,9 +4334,9 @@
     pub Reserved4: [u8; 224],
 }
 #[cfg(target_arch = "x86")]
-impl ::core::marker::Copy for XSAVE_FORMAT {}
+impl Copy for XSAVE_FORMAT {}
 #[cfg(target_arch = "x86")]
-impl ::core::clone::Clone for XSAVE_FORMAT {
+impl Clone for XSAVE_FORMAT {
     fn clone(&self) -> Self {
         *self
     }
diff --git a/rust-bors.toml b/rust-bors.toml
index 54f4f64..f27eb23 100644
--- a/rust-bors.toml
+++ b/rust-bors.toml
@@ -1 +1 @@
-timeout = 7200
+timeout = 14400
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 9c43160..818a7da 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -131,6 +131,8 @@
   "riscv32gc-unknown-linux-musl install directory")
 v("musl-root-riscv64gc", "target.riscv64gc-unknown-linux-musl.musl-root",
   "riscv64gc-unknown-linux-musl install directory")
+v("musl-root-loongarch64", "target.loongarch64-unknown-linux-musl.musl-root",
+  "loongarch64-unknown-linux-musl install directory")
 v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
   "rootfs in qemu testing, you probably don't want to use this")
 v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index 070d951..98495f2 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -7,6 +7,7 @@
 
 use std::io::Write;
 use std::process;
+use std::str::FromStr;
 use std::{
     env,
     fs::{self, OpenOptions},
@@ -136,16 +137,25 @@
     let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id;
     let warned_id_path = config.out.join("bootstrap").join(".last-warned-change-id");
 
-    if let Some(id) = config.change_id {
+    if let Some(mut id) = config.change_id {
         if id == latest_change_id {
             return None;
         }
 
-        if let Ok(last_warned_id) = fs::read_to_string(&warned_id_path) {
-            if latest_change_id.to_string() == last_warned_id {
-                return None;
+        // Always try to use `change-id` from .last-warned-change-id first. If it doesn't exist,
+        // then use the one from the config.toml. This way we never show the same warnings
+        // more than once.
+        if let Ok(t) = fs::read_to_string(&warned_id_path) {
+            let last_warned_id =
+                usize::from_str(&t).expect(&format!("{} is corrupted.", warned_id_path.display()));
+
+            // We only use the last_warned_id if it exists in `CONFIG_CHANGE_HISTORY`.
+            // Otherwise, we may retrieve all the changes if it's not the highest value.
+            // For better understanding, refer to `change_tracker::find_recent_config_change_ids`.
+            if CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == last_warned_id) {
+                id = last_warned_id;
             }
-        }
+        };
 
         let changes = find_recent_config_change_ids(id);
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh
old mode 100644
new mode 100755
index 324dd5f..b22d60f
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh
@@ -1,9 +1,11 @@
-#!/bin/sh
+#!/usr/bin/env bash
 
 set -ex
 
 cd $1
 
+source shared.sh
+
 # Setting up folders for GCC
 git clone https://github.com/antoyo/gcc gcc-src
 cd gcc-src
@@ -14,15 +16,17 @@
 cd ../gcc-build
 
 # Building GCC.
-../gcc-src/configure \
+hide_output \
+  ../gcc-src/configure \
     --enable-host-shared \
     --enable-languages=jit \
     --enable-checking=release \
     --disable-bootstrap \
     --disable-multilib \
-    --prefix=$(pwd)/../gcc-install
-make
-make install
+    --prefix=$(pwd)/../gcc-install \
+
+hide_output make -j$(nproc)
+hide_output make install
 
 rm -rf ../gcc-src
 ln -s /scripts/gcc-install/lib/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
index 6540a50..4fc2b2e 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
@@ -59,8 +59,9 @@
 
 COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
 
+COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
 COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
 
-RUN sh /scripts/build-gccjit.sh /scripts
+RUN /scripts/build-gccjit.sh /scripts
 
 ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
index ed4e197..7c2ecd1 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
@@ -58,8 +58,9 @@
 
 COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
 
+COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
 COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
 
-RUN sh /scripts/build-gccjit.sh /scripts
+RUN /scripts/build-gccjit.sh /scripts
 
 ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index a03577b..6f72056 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -95,9 +95,10 @@
 
 ENV HOST_TARGET x86_64-unknown-linux-gnu
 
+COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
 COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
 
-RUN sh /scripts/build-gccjit.sh /scripts
+RUN /scripts/build-gccjit.sh /scripts
 
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
   NODE_PATH=`npm root -g` python3 ../x.py test tests/rustdoc-gui --stage 2 \
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index bd5447a..740eb75 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -92,21 +92,38 @@
     # Print docker version
     docker --version
 
-    # On non-CI or PR jobs, we don't have permissions to write to the registry cache, so we should
-    # not use `docker login` nor caching.
-    if [[ "$CI" == "" ]] || [[ "$PR_CI_JOB" == "1" ]];
+    REGISTRY=ghcr.io
+    # PR CI runs on rust-lang, but we want to use the cache from rust-lang-ci
+    REGISTRY_USERNAME=rust-lang-ci
+    # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
+    IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
+    # Tag used to cache the Docker build
+    # It seems that it cannot be the same as $IMAGE_TAG, otherwise it overwrites the cache
+    CACHE_IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci-cache:${cksum}
+
+    # On non-CI jobs, we don't do any caching.
+    if [[ "$CI" == "" ]];
     then
         retry docker build --rm -t rust-ci -f "$dockerfile" "$context"
-    else
-        REGISTRY=ghcr.io
-        # Most probably rust-lang-ci, but in general the owner of the repository where CI runs
-        REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER}
-        # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
-        IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
-        # Tag used to cache the Docker build
-        # It seems that it cannot be the same as $IMAGE_TAG, otherwise it overwrites the cache
-        CACHE_IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci-cache:${cksum}
+    # On PR CI jobs, we don't have permissions to write to the registry cache,
+    # but we can still read from it.
+    elif [[ "$PR_CI_JOB" == "1" ]];
+    then
+        # Enable a new Docker driver so that --cache-from works with a registry backend
+        docker buildx create --use --driver docker-container
 
+        # Build the image using registry caching backend
+        retry docker \
+          buildx \
+          build \
+          --rm \
+          -t rust-ci \
+          -f "$dockerfile" \
+          --cache-from type=registry,ref=${CACHE_IMAGE_TAG} \
+          --output=type=docker \
+          "$context"
+    # On auto/try builds, we can also write to the cache.
+    else
         # Log into the Docker registry, so that we can read/write cache and the final image
         echo ${DOCKER_TOKEN} | docker login ${REGISTRY} \
             --username ${REGISTRY_USERNAME} \
diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md
index 7780f21..185a3ba 100644
--- a/src/doc/rustc/src/instrument-coverage.md
+++ b/src/doc/rustc/src/instrument-coverage.md
@@ -352,7 +352,7 @@
 instrumentation. Pass one or more of the following values, separated by commas.
 
 - `branch` or `no-branch`
-  - Placeholder for potential branch coverage support in the future.
+  - Enables or disables branch coverage instrumentation.
 
 ## Other references
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 285c773..2ebbf5e1 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -33,16 +33,14 @@
 target | notes
 -------|-------
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
-`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+) [^windows-support] [^x86_32-floats-return-ABI]
-`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+) [^windows-support] [^x86_32-floats-return-ABI]
+`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+) [^x86_32-floats-return-ABI]
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
 `x86_64-apple-darwin` | 64-bit macOS (10.12+, Sierra+)
-`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+) [^windows-support]
-`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+) [^windows-support]
+`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+)
+`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
 
-[^windows-support]: Only Windows 10 currently undergoes automated testing. Earlier versions of Windows rely on testing and support from the community.
-
 [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. See [issue #114479][x86-32-float-issue].
 
 [77071]: https://github.com/rust-lang/rust/issues/77071
diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md
index 9f90e74..b2ddbfd 100644
--- a/src/doc/rustc/src/platform-support/openharmony.md
+++ b/src/doc/rustc/src/platform-support/openharmony.md
@@ -96,9 +96,34 @@
 
 Future versions of the OpenHarmony SDK will avoid the need for this process.
 
-## Building the target
+## Building Rust programs
 
-To build a rust toolchain, create a `config.toml` with the following contents:
+Rustup ships pre-compiled artifacts for this target, which you can install with:
+```sh
+rustup target add aarch64-unknown-linux-ohos
+rustup target add armv7-unknown-linux-ohos
+rustup target add x86_64-unknown-linux-ohos
+```
+
+You will need to configure the linker to use in `~/.cargo/config.toml`:
+```toml
+[target.aarch64-unknown-linux-ohos]
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+linker = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
+
+[target.armv7-unknown-linux-ohos]
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+linker = "/path/to/armv7-unknown-linux-ohos-clang.sh"
+
+[target.x86_64-unknown-linux-ohos]
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+linker = "/path/to/x86_64-unknown-linux-ohos-clang.sh"
+```
+
+## Building the target from source
+
+Instead of using `rustup`, you can instead build a rust toolchain from source.
+Create a `config.toml` with the following contents:
 
 ```toml
 profile = "compiler"
@@ -130,28 +155,6 @@
 linker  = "/path/to/x86_64-unknown-linux-ohos-clang.sh"
 ```
 
-## Building Rust programs
-
-Rust does not yet ship pre-compiled artifacts for this target. To compile for
-this target, you will either need to build Rust with the target enabled (see
-"Building the target" above), or build your own copy of `core` by using
-`build-std` or similar.
-
-You will need to configure the linker to use in `~/.cargo/config`:
-```toml
-[target.aarch64-unknown-linux-ohos]
-ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
-linker = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
-
-[target.armv7-unknown-linux-ohos]
-ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
-linker = "/path/to/armv7-unknown-linux-ohos-clang.sh"
-
-[target.x86_64-unknown-linux-ohos]
-ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
-linker = "/path/to/x86_64-unknown-linux-ohos-clang.sh"
-```
-
 ## Testing
 
 Running the Rust testsuite is possible, but currently difficult due to the way
diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md
index 8fb155e..e691750 100644
--- a/src/doc/rustc/src/platform-support/unknown-uefi.md
+++ b/src/doc/rustc/src/platform-support/unknown-uefi.md
@@ -51,7 +51,7 @@
 By default, the UEFI targets use the `link`-flavor of the LLVM linker `lld` to
 link binaries into the final PE32+ file suffixed with `*.efi`. The PE subsystem
 is set to `EFI_APPLICATION`, but can be modified by passing `/subsystem:<...>`
-to the linker. Similarly, the entry-point is to to `efi_main` but can be
+to the linker. Similarly, the entry-point is set to `efi_main` but can be
 changed via `/entry:<...>`. The panic-strategy is set to `abort`,
 
 The UEFI specification is available online for free:
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index b46d80eb..fe5cb52 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -427,3 +427,32 @@
 Rustdoc only supports Rust source code and Markdown input formats. If the
 file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file.
 Otherwise, it assumes that the input file is Rust.
+
+## `--test-builder`: `rustc`-like program to build tests
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc --test-builder /path/to/rustc src/lib.rs
+```
+
+Rustdoc will use the provided program to compile tests instead of the default `rustc` program from
+the sysroot.
+
+## `--test-builder-wrapper`: wrap calls to the test builder
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc --test-builder-wrapper /path/to/rustc-wrapper src/lib.rs
+$ rustdoc \
+    --test-builder-wrapper rustc-wrapper1 \
+    --test-builder-wrapper rustc-wrapper2 \
+    --test-builder rustc \
+    src/lib.rs
+```
+
+Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper program.
+The first argument to the program will be the test builder program.
+
+This flag can be passed multiple times to nest wrappers.
diff --git a/src/doc/rustdoc/src/read-documentation/search.md b/src/doc/rustdoc/src/read-documentation/search.md
index b5f4060..e2def14 100644
--- a/src/doc/rustdoc/src/read-documentation/search.md
+++ b/src/doc/rustdoc/src/read-documentation/search.md
@@ -63,11 +63,12 @@
 the standard library and functions that are included in the results list:
 
 | Query | Results |
-|-------|--------|
+|-------|---------|
 | [`usize -> vec`][] | `slice::repeat` and `Vec::with_capacity` |
 | [`vec, vec -> bool`][] | `Vec::eq` |
 | [`option<T>, fnonce -> option<U>`][] | `Option::map` and `Option::and_then` |
-| [`option<T>, fnonce -> option<T>`][] | `Option::filter` and `Option::inspect` |
+| [`option<T>, (fnonce (T) -> bool) -> option<T>`][optionfilter] | `Option::filter` |
+| [`option<T>, (T -> bool) -> option<T>`][optionfilter2] | `Option::filter` |
 | [`option -> default`][] | `Option::unwrap_or_default` |
 | [`stdout, [u8]`][stdoutu8] | `Stdout::write` |
 | [`any -> !`][] | `panic::panic_any` |
@@ -77,7 +78,8 @@
 [`usize -> vec`]: ../../std/vec/struct.Vec.html?search=usize%20-%3E%20vec&filter-crate=std
 [`vec, vec -> bool`]: ../../std/vec/struct.Vec.html?search=vec,%20vec%20-%3E%20bool&filter-crate=std
 [`option<T>, fnonce -> option<U>`]: ../../std/vec/struct.Vec.html?search=option<T>%2C%20fnonce%20->%20option<U>&filter-crate=std
-[`option<T>, fnonce -> option<T>`]: ../../std/vec/struct.Vec.html?search=option<T>%2C%20fnonce%20->%20option<T>&filter-crate=std
+[optionfilter]: ../../std/vec/struct.Vec.html?search=option<T>%2C+(fnonce+(T)+->+bool)+->+option<T>&filter-crate=std
+[optionfilter2]: ../../std/vec/struct.Vec.html?search=option<T>%2C+(T+->+bool)+->+option<T>&filter-crate=std
 [`option -> default`]: ../../std/vec/struct.Vec.html?search=option%20-%3E%20default&filter-crate=std
 [`any -> !`]: ../../std/vec/struct.Vec.html?search=any%20-%3E%20!&filter-crate=std
 [stdoutu8]: ../../std/vec/struct.Vec.html?search=stdout%2C%20[u8]&filter-crate=std
@@ -151,16 +153,26 @@
 
 But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
 
+To search for a function that accepts a function as a parameter,
+like `Iterator::all`, wrap the nested signature in parenthesis,
+as in [`Iterator<T>, (T -> bool) -> bool`][iterator-all].
+You can also search for a specific closure trait,
+such as `Iterator<T>, (FnMut(T) -> bool) -> bool`,
+but you need to know which one you want.
+
+[iterator-all]: ../../std/vec/struct.Vec.html?search=Iterator<T>%2C+(T+->+bool)+->+bool&filter-crate=std
+
 ### Primitives with Special Syntax
 
-| Shorthand | Explicit names                                   |
-| --------- | ------------------------------------------------ |
-| `[]`      | `primitive:slice` and/or `primitive:array`       |
-| `[T]`     | `primitive:slice<T>` and/or `primitive:array<T>` |
-| `()`      | `primitive:unit` and/or `primitive:tuple`        |
-| `(T)`     | `T`                                              |
-| `(T,)`    | `primitive:tuple<T>`                             |
-| `!`       | `primitive:never`                                |
+| Shorthand        | Explicit names                                    |
+| ---------------- | ------------------------------------------------- |
+| `[]`             | `primitive:slice` and/or `primitive:array`        |
+| `[T]`            | `primitive:slice<T>` and/or `primitive:array<T>`  |
+| `()`             | `primitive:unit` and/or `primitive:tuple`         |
+| `(T)`            | `T`                                               |
+| `(T,)`           | `primitive:tuple<T>`                              |
+| `!`              | `primitive:never`                                 |
+| `(T, U -> V, W)` | `fn(T, U) -> (V, W)`, `Fn`, `FnMut`, and `FnOnce` |
 
 When searching for `[]`, Rustdoc will return search results with either slices
 or arrays. If you know which one you want, you can force it to return results
@@ -180,6 +192,10 @@
 its own. That is, `(u32)` matches `(u32,)` for the exact same reason that it
 also matches `Result<u32, Error>`.
 
+The `->` operator has lower precedence than comma. If it's not wrapped
+in brackets, it delimits the return value for the function being searched for.
+To search for functions that take functions as parameters, use parenthesis.
+
 ### Limitations and quirks of type-based search
 
 Type-based search is still a buggy, experimental, work-in-progress feature.
@@ -218,9 +234,6 @@
 
   * Searching for lifetimes is not supported.
 
-  * It's impossible to search for closures based on their parameters or
-    return values.
-
   * It's impossible to search based on the length of an array.
 
 ## Item filtering
@@ -237,19 +250,21 @@
 
 ```text
 ident = *(ALPHA / DIGIT / "_")
-path = ident *(DOUBLE-COLON ident) [!]
+path = ident *(DOUBLE-COLON ident) [BANG]
 slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
 tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN
-arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / [!])
+arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like)
 type-sep = COMMA/WS *(COMMA/WS)
-nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) [ return-args ]
 generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
-generics = OPEN-ANGLE-BRACKET [ generic-arg-list ] *(type-sep)
+normal-generics = OPEN-ANGLE-BRACKET [ generic-arg-list ] *(type-sep)
             CLOSE-ANGLE-BRACKET
+fn-like-generics = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN [ RETURN-ARROW arg ]
+generics = normal-generics / fn-like-generics
 return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
 
 exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
-type-search = [ nonempty-arg-list ] [ return-args ]
+type-search = [ nonempty-arg-list ]
 
 query = *WS (exact-search / type-search) *WS
 
@@ -294,6 +309,7 @@
 COMMA = ","
 RETURN-ARROW = "->"
 EQUAL = "="
+BANG = "!"
 
 ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
 DIGIT = %x30-39
diff --git a/src/doc/unstable-book/src/compiler-flags/coverage-options.md b/src/doc/unstable-book/src/compiler-flags/coverage-options.md
index 105dce6..450573c 100644
--- a/src/doc/unstable-book/src/compiler-flags/coverage-options.md
+++ b/src/doc/unstable-book/src/compiler-flags/coverage-options.md
@@ -5,4 +5,4 @@
 
 Multiple options can be passed, separated by commas. Valid options are:
 
-- `branch` or `no-branch`: Placeholder for future branch coverage support.
+- `branch` or `no-branch`: Enables or disables branch coverage instrumentation.
diff --git a/src/doc/unstable-book/src/language-features/f128.md b/src/doc/unstable-book/src/language-features/f128.md
new file mode 100644
index 0000000..0cc5f67
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/f128.md
@@ -0,0 +1,9 @@
+# `f128`
+
+The tracking issue for this feature is: [#116909]
+
+[#116909]: https://github.com/rust-lang/rust/issues/116909
+
+---
+
+Enable the `f128` type for  IEEE 128-bit floating numbers (quad precision).
diff --git a/src/doc/unstable-book/src/language-features/f16.md b/src/doc/unstable-book/src/language-features/f16.md
new file mode 100644
index 0000000..efb07a5
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/f16.md
@@ -0,0 +1,9 @@
+# `f16`
+
+The tracking issue for this feature is: [#116909]
+
+[#116909]: https://github.com/rust-lang/rust/issues/116909
+
+---
+
+Enable the `f16` type for  IEEE 16-bit floating numbers (half precision).
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 77a78f5..6f86c64 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -62,6 +62,9 @@
         attrs_without_docs.as_ref().map(|(attrs, def_id)| (&attrs[..], *def_id));
 
     let import_def_id = attrs.and_then(|(_, def_id)| def_id);
+
+    let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
+
     let kind = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, ItemType::Trait);
@@ -131,7 +134,7 @@
             cx.with_param_env(did, |cx| clean::ConstantItem(build_const(cx, did)))
         }
         Res::Def(DefKind::Macro(kind), did) => {
-            let mac = build_macro(cx, did, name, import_def_id, kind);
+            let mac = build_macro(cx, did, name, import_def_id, kind, attrs.is_doc_hidden());
 
             let type_kind = match kind {
                 MacroKind::Bang => ItemType::Macro,
@@ -144,7 +147,6 @@
         _ => return None,
     };
 
-    let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
     cx.inlined.insert(did.into());
     let mut item =
         clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg);
@@ -751,6 +753,7 @@
     name: Symbol,
     import_def_id: Option<DefId>,
     macro_kind: MacroKind,
+    is_doc_hidden: bool,
 ) -> clean::ItemKind {
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
         LoadedMacro::MacroDef(item_def, _) => match macro_kind {
@@ -758,7 +761,14 @@
                 if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
                     let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id));
                     clean::MacroItem(clean::Macro {
-                        source: utils::display_macro_source(cx, name, def, def_id, vis),
+                        source: utils::display_macro_source(
+                            cx,
+                            name,
+                            def,
+                            def_id,
+                            vis,
+                            is_doc_hidden,
+                        ),
                     })
                 } else {
                     unreachable!()
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b32d3ad..dfc026fe 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -149,8 +149,7 @@
 }
 
 fn is_glob_import(tcx: TyCtxt<'_>, import_id: LocalDefId) -> bool {
-    if let Some(node) = tcx.opt_hir_node_by_def_id(import_id)
-        && let hir::Node::Item(item) = node
+    if let hir::Node::Item(item) = tcx.hir_node_by_def_id(import_id)
         && let hir::ItemKind::Use(_, use_kind) = item.kind
     {
         use_kind == hir::UseKind::Glob
@@ -1612,8 +1611,7 @@
             'reexps: for reexp in child.reexport_chain.iter() {
                 if let Some(use_def_id) = reexp.id()
                     && let Some(local_use_def_id) = use_def_id.as_local()
-                    && let Some(hir::Node::Item(item)) =
-                        cx.tcx.opt_hir_node_by_def_id(local_use_def_id)
+                    && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_use_def_id)
                     && !item.ident.name.is_empty()
                     && let hir::ItemKind::Use(path, _) = item.kind
                 {
@@ -2796,7 +2794,8 @@
             ItemKind::Macro(ref macro_def, MacroKind::Bang) => {
                 let ty_vis = cx.tcx.visibility(def_id);
                 MacroItem(Macro {
-                    source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
+                    // FIXME this shouldn't be false
+                    source: display_macro_source(cx, name, macro_def, def_id, ty_vis, false),
                 })
             }
             ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index c35baeb..a51f636 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1161,7 +1161,7 @@
         false
     }
 
-    fn is_doc_hidden(&self) -> bool {
+    pub(crate) fn is_doc_hidden(&self) -> bool {
         self.has_doc_flag(sym::hidden)
     }
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 57916ff..0b20cca 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -625,6 +625,7 @@
     def: &ast::MacroDef,
     def_id: DefId,
     vis: ty::Visibility<DefId>,
+    is_doc_hidden: bool,
 ) -> String {
     // Extract the spans of all matchers. They represent the "interface" of the macro.
     let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]);
@@ -635,7 +636,7 @@
         if matchers.len() <= 1 {
             format!(
                 "{vis}macro {name}{matchers} {{\n    ...\n}}",
-                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
+                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
                 matchers = matchers
                     .map(|matcher| render_macro_matcher(cx.tcx, matcher))
                     .collect::<String>(),
@@ -643,7 +644,7 @@
         } else {
             format!(
                 "{vis}macro {name} {{\n{arms}}}",
-                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
+                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
                 arms = render_macro_arms(cx.tcx, matchers, ","),
             )
         }
@@ -664,9 +665,10 @@
         def_id = id;
         if tcx.is_doc_hidden(def_id.to_def_id()) {
             return true;
-        } else if let Some(node) = tcx.opt_hir_node_by_def_id(def_id)
-            && matches!(node, hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),)
-        {
+        } else if matches!(
+            tcx.hir_node_by_def_id(def_id),
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. })
+        ) {
             // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
             // on them, they don't inherit it from the parent context.
             return false;
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 4b1a417..be7e319 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -130,6 +130,9 @@
     /// default to loading from `$sysroot/bin/rustc`.
     pub(crate) test_builder: Option<PathBuf>,
 
+    /// Run these wrapper instead of rustc directly
+    pub(crate) test_builder_wrappers: Vec<PathBuf>,
+
     // Options that affect the documentation process
     /// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items
     /// with and without documentation.
@@ -204,6 +207,7 @@
             .field("enable-per-target-ignores", &self.enable_per_target_ignores)
             .field("run_check", &self.run_check)
             .field("no_run", &self.no_run)
+            .field("test_builder_wrappers", &self.test_builder_wrappers)
             .field("nocapture", &self.nocapture)
             .field("scrape_examples_options", &self.scrape_examples_options)
             .field("unstable_features", &self.unstable_features)
@@ -521,6 +525,8 @@
             dcx.fatal("the `--test` flag must be passed to enable `--no-run`");
         }
 
+        let test_builder_wrappers =
+            matches.opt_strs("test-builder-wrapper").iter().map(PathBuf::from).collect();
         let out_dir = matches.opt_str("out-dir").map(|s| PathBuf::from(&s));
         let output = matches.opt_str("output").map(|s| PathBuf::from(&s));
         let output = match (out_dir, output) {
@@ -727,6 +733,7 @@
             test_builder,
             run_check,
             no_run,
+            test_builder_wrappers,
             nocapture,
             crate_name,
             output_format,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index d446b78..c6eb7be 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -25,7 +25,7 @@
 use std::env;
 use std::io::{self, Write};
 use std::panic;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 use std::str;
 use std::sync::atomic::{AtomicUsize, Ordering};
@@ -306,6 +306,18 @@
     input + &exe_suffix
 }
 
+fn wrapped_rustc_command(rustc_wrappers: &[PathBuf], rustc_binary: &Path) -> Command {
+    let mut args = rustc_wrappers.iter().map(PathBuf::as_path).chain([rustc_binary].into_iter());
+
+    let exe = args.next().expect("unable to create rustc command");
+    let mut command = Command::new(exe);
+    for arg in args {
+        command.arg(arg);
+    }
+
+    command
+}
+
 fn run_test(
     test: &str,
     crate_name: &str,
@@ -334,7 +346,7 @@
         .test_builder
         .as_deref()
         .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
-    let mut compiler = Command::new(&rustc_binary);
+    let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
     compiler.arg("--crate-type").arg("bin");
     for cfg in &rustdoc_options.cfgs {
         compiler.arg("--cfg").arg(&cfg);
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index afd5eb4..312765d 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -29,8 +29,7 @@
 use itertools::Itertools;
 
 use crate::clean::{
-    self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, ItemId,
-    PrimitiveType,
+    self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType,
 };
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -1506,20 +1505,18 @@
 }
 
 pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
-    visibility: Option<ty::Visibility<DefId>>,
-    item_did: ItemId,
+    item: &clean::Item,
     cx: &'a Context<'tcx>,
 ) -> impl Display + 'a + Captures<'tcx> {
     use std::fmt::Write as _;
-
-    let to_print: Cow<'static, str> = match visibility {
+    let vis: Cow<'static, str> = match item.visibility(cx.tcx()) {
         None => "".into(),
         Some(ty::Visibility::Public) => "pub ".into(),
         Some(ty::Visibility::Restricted(vis_did)) => {
             // FIXME(camelid): This may not work correctly if `item_did` is a module.
             //                 However, rustdoc currently never displays a module's
             //                 visibility, so it shouldn't matter.
-            let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
+            let parent_module = find_nearest_parent_module(cx.tcx(), item.item_id.expect_def_id());
 
             if vis_did.is_crate_root() {
                 "pub(crate) ".into()
@@ -1547,7 +1544,15 @@
             }
         }
     };
-    display_fn(move |f| f.write_str(&to_print))
+
+    let is_doc_hidden = item.is_doc_hidden();
+    display_fn(move |f| {
+        if is_doc_hidden {
+            f.write_str("#[doc(hidden)] ")?;
+        }
+
+        f.write_str(&vis)
+    })
 }
 
 /// This function is the same as print_with_space, except that it renders no links.
@@ -1557,8 +1562,9 @@
     visibility: Option<ty::Visibility<DefId>>,
     tcx: TyCtxt<'tcx>,
     item_did: DefId,
+    is_doc_hidden: bool,
 ) -> impl Display + 'a + Captures<'tcx> {
-    let to_print: Cow<'static, str> = match visibility {
+    let vis: Cow<'static, str> = match visibility {
         None => "".into(),
         Some(ty::Visibility::Public) => "pub ".into(),
         Some(ty::Visibility::Restricted(vis_did)) => {
@@ -1582,7 +1588,12 @@
             }
         }
     };
-    display_fn(move |f| f.write_str(&to_print))
+    display_fn(move |f| {
+        if is_doc_hidden {
+            f.write_str("#[doc(hidden)] ")?;
+        }
+        f.write_str(&vis)
+    })
 }
 
 pub(crate) trait PrintWithSpace {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index fe83095..6c50404 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -883,7 +883,7 @@
         w,
         "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
         indent = " ".repeat(indent),
-        vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+        vis = visibility_print_with_space(it, cx),
         href = assoc_href_attr(it, link, cx),
         name = it.name.as_ref().unwrap(),
         generics = generics.print(cx),
@@ -912,12 +912,11 @@
     indent: usize,
     cx: &Context<'_>,
 ) {
-    let tcx = cx.tcx();
     write!(
         w,
         "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
         indent = " ".repeat(indent),
-        vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+        vis = visibility_print_with_space(it, cx),
         href = assoc_href_attr(it, link, cx),
         name = it.name.as_ref().unwrap(),
         generics = generics.print(cx),
@@ -945,7 +944,7 @@
     let tcx = cx.tcx();
     let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
     let name = meth.name.as_ref().unwrap();
-    let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
+    let vis = visibility_print_with_space(meth, cx).to_string();
     let defaultness = print_default_space(meth.is_default());
     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
     // this condition.
@@ -1698,9 +1697,10 @@
                     let id = cx.derive_id(format!("{item_type}.{name}"));
                     let source_id = trait_
                         .and_then(|trait_| {
-                            trait_.items.iter().find(|item| {
-                                item.name.map(|n| n.as_str().eq(name.as_str())).unwrap_or(false)
-                            })
+                            trait_
+                                .items
+                                .iter()
+                                .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
                         })
                         .map(|item| format!("{}.{name}", item.type_()));
                     write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d588f21..5d4f1ac 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -445,14 +445,14 @@
                     Some(src) => write!(
                         w,
                         "<div class=\"item-name\"><code>{}extern crate {} as {};",
-                        visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
+                        visibility_print_with_space(myitem, cx),
                         anchor(myitem.item_id.expect_def_id(), src, cx),
                         myitem.name.unwrap(),
                     ),
                     None => write!(
                         w,
                         "<div class=\"item-name\"><code>{}extern crate {};",
-                        visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
+                        visibility_print_with_space(myitem, cx),
                         anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
                     ),
                 }
@@ -491,7 +491,7 @@
                          <code>{vis}{imp}</code>\
                      </div>\
                      {stab_tags_before}{stab_tags}{stab_tags_after}",
-                    vis = visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
+                    vis = visibility_print_with_space(myitem, cx),
                     imp = import.print(cx),
                 );
                 w.write_str(ITEM_TABLE_ROW_CLOSE);
@@ -511,10 +511,16 @@
                     _ => "",
                 };
 
-                let visibility_emoji = match myitem.visibility(tcx) {
+                let visibility_and_hidden = match myitem.visibility(tcx) {
                     Some(ty::Visibility::Restricted(_)) => {
-                        "<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
+                        if myitem.is_doc_hidden() {
+                            // Don't separate with a space when there are two of them
+                            "<span title=\"Restricted Visibility\">&nbsp;🔒</span><span title=\"Hidden item\">👻</span> "
+                        } else {
+                            "<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
+                        }
                     }
+                    _ if myitem.is_doc_hidden() => "<span title=\"Hidden item\">&nbsp;👻</span> ",
                     _ => "",
                 };
 
@@ -530,13 +536,13 @@
                     w,
                     "<div class=\"item-name\">\
                         <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
-                        {visibility_emoji}\
+                        {visibility_and_hidden}\
                         {unsafety_flag}\
                         {stab_tags}\
                      </div>\
                      {docs_before}{docs}{docs_after}",
                     name = myitem.name.unwrap(),
-                    visibility_emoji = visibility_emoji,
+                    visibility_and_hidden = visibility_and_hidden,
                     stab_tags = extra_info_tags(myitem, item, tcx),
                     class = myitem.type_(),
                     unsafety_flag = unsafety_flag,
@@ -625,7 +631,7 @@
     let unsafety = header.unsafety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let asyncness = header.asyncness.print_with_space();
-    let visibility = visibility_print_with_space(it.visibility(tcx), it.item_id, cx).to_string();
+    let visibility = visibility_print_with_space(it, cx).to_string();
     let name = it.name.unwrap();
 
     let generics_len = format!("{:#}", f.generics.print(cx)).len();
@@ -682,7 +688,7 @@
             w,
             "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}",
             attrs = render_attributes_in_pre(it, "", cx),
-            vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+            vis = visibility_print_with_space(it, cx),
             unsafety = t.unsafety(tcx).print_with_space(),
             is_auto = if t.is_auto(tcx) { "auto " } else { "" },
             name = it.name.unwrap(),
@@ -1237,7 +1243,7 @@
                 w,
                 "{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
                 attrs = render_attributes_in_pre(it, "", cx),
-                vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+                vis = visibility_print_with_space(it, cx),
                 name = it.name.unwrap(),
                 generics = t.generics.print(cx),
                 where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
@@ -1516,14 +1522,13 @@
 }
 
 fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) {
-    let tcx = cx.tcx();
     let count_variants = e.variants().count();
     wrap_item(w, |w| {
         render_attributes_in_code(w, it, cx);
         write!(
             w,
             "{}enum {}{}",
-            visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+            visibility_print_with_space(it, cx),
             it.name.unwrap(),
             e.generics.print(cx),
         );
@@ -1854,7 +1859,7 @@
         write!(
             w,
             "{vis}const {name}{generics}: {typ}{where_clause}",
-            vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+            vis = visibility_print_with_space(it, cx),
             name = it.name.unwrap(),
             generics = c.generics.print(cx),
             typ = c.type_.print(cx),
@@ -1958,7 +1963,7 @@
         write!(
             buffer,
             "{vis}static {mutability}{name}: {typ}",
-            vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+            vis = visibility_print_with_space(it, cx),
             mutability = s.mutability.print_with_space(),
             name = it.name.unwrap(),
             typ = s.type_.print(cx)
@@ -1976,7 +1981,7 @@
         write!(
             buffer,
             "    {}type {};\n}}",
-            visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+            visibility_print_with_space(it, cx),
             it.name.unwrap(),
         )
         .unwrap();
@@ -2133,13 +2138,7 @@
     cx: &'a Context<'cx>,
 ) -> impl fmt::Display + 'a + Captures<'cx> {
     display_fn(move |mut f| {
-        let tcx = cx.tcx();
-        write!(
-            f,
-            "{}union {}",
-            visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
-            it.name.unwrap(),
-        )?;
+        write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?;
 
         let where_displayed = g
             .map(|g| {
@@ -2169,7 +2168,7 @@
                 write!(
                     f,
                     "    {}{}: {},\n",
-                    visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
+                    visibility_print_with_space(field, cx),
                     field.name.unwrap(),
                     ty.print(cx)
                 )?;
@@ -2197,11 +2196,10 @@
     structhead: bool,
     cx: &Context<'_>,
 ) {
-    let tcx = cx.tcx();
     write!(
         w,
         "{}{}{}",
-        visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+        visibility_print_with_space(it, cx),
         if structhead { "struct " } else { "" },
         it.name.unwrap()
     );
@@ -2230,7 +2228,6 @@
     has_stripped_entries: bool,
     cx: &Context<'_>,
 ) {
-    let tcx = cx.tcx();
     match ty {
         None => {
             let where_displayed =
@@ -2254,7 +2251,7 @@
                     write!(
                         w,
                         "\n{tab}    {vis}{name}: {ty},",
-                        vis = visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
+                        vis = visibility_print_with_space(field, cx),
                         name = field.name.unwrap(),
                         ty = ty.print(cx),
                     );
@@ -2290,16 +2287,7 @@
                     match *field.kind {
                         clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
                         clean::StructFieldItem(ref ty) => {
-                            write!(
-                                w,
-                                "{}{}",
-                                visibility_print_with_space(
-                                    field.visibility(tcx),
-                                    field.item_id,
-                                    cx
-                                ),
-                                ty.print(cx),
-                            )
+                            write!(w, "{}{}", visibility_print_with_space(field, cx), ty.print(cx),)
                         }
                         _ => unreachable!(),
                     }
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index cb05908..f153a90 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -4,6 +4,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
+use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
 use thin_vec::ThinVec;
@@ -566,6 +567,7 @@
         // The type parameters are converted to generics in `simplify_fn_type`
         clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
         clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
+        clean::BareFunction(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Fn)),
         clean::Tuple(ref n) if n.is_empty() => {
             Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit))
         }
@@ -584,7 +586,7 @@
             }
         }
         // Not supported yet
-        clean::BareFunction(_) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
+        clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
     }
 }
 
@@ -785,6 +787,42 @@
             );
         }
         res.push(get_index_type(arg, ty_generics, rgen));
+    } else if let Type::BareFunction(ref bf) = *arg {
+        let mut ty_generics = Vec::new();
+        for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
+            simplify_fn_type(
+                self_,
+                generics,
+                ty,
+                tcx,
+                recurse + 1,
+                &mut ty_generics,
+                rgen,
+                is_return,
+                cache,
+            );
+        }
+        // The search index, for simplicity's sake, represents fn pointers and closures
+        // the same way: as a tuple for the parameters, and an associated type for the
+        // return type.
+        let mut ty_output = Vec::new();
+        simplify_fn_type(
+            self_,
+            generics,
+            &bf.decl.output,
+            tcx,
+            recurse + 1,
+            &mut ty_output,
+            rgen,
+            is_return,
+            cache,
+        );
+        let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
+        res.push(RenderType {
+            id: get_index_type_id(&arg, rgen),
+            bindings: Some(ty_bindings),
+            generics: Some(ty_generics),
+        });
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
         // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 7995a33..875ebe2 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 /* global addClass, getNakedUrl, getSettingValue */
 /* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
 
@@ -80,6 +81,13 @@
 const TY_GENERIC = itemTypes.indexOf("generic");
 const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
 
+// Hard limit on how deep to recurse into generics when doing type-driven search.
+// This needs limited, partially because
+// a search for `Ty` shouldn't match `WithInfcx<ParamEnvAnd<Vec<ConstTy<Interner<Ty=Ty>>>>>`,
+// but mostly because this is the simplest and most principled way to limit the number
+// of permutations we need to check.
+const UNBOXING_LIMIT = 5;
+
 // In the search display, allows to switch between tabs.
 function printTab(nb) {
     let iter = 0;
@@ -245,33 +253,49 @@
      *
      * @type {Map<string, {id: integer, assocOnly: boolean}>}
      */
-    let typeNameIdMap;
+    const typeNameIdMap = new Map();
     const ALIASES = new Map();
 
     /**
      * Special type name IDs for searching by array.
      */
-    let typeNameIdOfArray;
+    const typeNameIdOfArray = buildTypeMapIndex("array");
     /**
      * Special type name IDs for searching by slice.
      */
-    let typeNameIdOfSlice;
+    const typeNameIdOfSlice = buildTypeMapIndex("slice");
     /**
      * Special type name IDs for searching by both array and slice (`[]` syntax).
      */
-    let typeNameIdOfArrayOrSlice;
+    const typeNameIdOfArrayOrSlice = buildTypeMapIndex("[]");
     /**
      * Special type name IDs for searching by tuple.
      */
-    let typeNameIdOfTuple;
+    const typeNameIdOfTuple = buildTypeMapIndex("tuple");
     /**
      * Special type name IDs for searching by unit.
      */
-    let typeNameIdOfUnit;
+    const typeNameIdOfUnit = buildTypeMapIndex("unit");
     /**
      * Special type name IDs for searching by both tuple and unit (`()` syntax).
      */
-    let typeNameIdOfTupleOrUnit;
+    const typeNameIdOfTupleOrUnit = buildTypeMapIndex("()");
+    /**
+     * Special type name IDs for searching `fn`.
+     */
+    const typeNameIdOfFn = buildTypeMapIndex("fn");
+    /**
+     * Special type name IDs for searching `fnmut`.
+     */
+    const typeNameIdOfFnMut = buildTypeMapIndex("fnmut");
+    /**
+     * Special type name IDs for searching `fnonce`.
+     */
+    const typeNameIdOfFnOnce = buildTypeMapIndex("fnonce");
+    /**
+     * Special type name IDs for searching higher order functions (`->` syntax).
+     */
+    const typeNameIdOfHof = buildTypeMapIndex("->");
 
     /**
      * Add an item to the type Name->ID map, or, if one already exists, use it.
@@ -464,6 +488,21 @@
         }
     }
 
+    function makePrimitiveElement(name, extra) {
+        return Object.assign({
+            name,
+            id: null,
+            fullPath: [name],
+            pathWithoutLast: [],
+            pathLast: name,
+            normalizedPathLast: name,
+            generics: [],
+            bindings: new Map(),
+            typeFilter: "primitive",
+            bindingName: null,
+        }, extra);
+    }
+
     /**
      * @param {ParsedQuery} query
      * @param {ParserState} parserState
@@ -501,18 +540,7 @@
             }
             const bindingName = parserState.isInBinding;
             parserState.isInBinding = null;
-            return {
-                name: "never",
-                id: null,
-                fullPath: ["never"],
-                pathWithoutLast: [],
-                pathLast: "never",
-                normalizedPathLast: "never",
-                generics: [],
-                bindings: new Map(),
-                typeFilter: "primitive",
-                bindingName,
-            };
+            return makePrimitiveElement("never", { bindingName });
         }
         const quadcolon = /::\s*::/.exec(path);
         if (path.startsWith("::")) {
@@ -558,7 +586,10 @@
                 // Syntactically, bindings are parsed as generics,
                 // but the query engine treats them differently.
                 if (gen.bindingName !== null) {
-                    bindings.set(gen.bindingName.name, [gen, ...gen.bindingName.generics]);
+                    if (gen.name !== null) {
+                        gen.bindingName.generics.unshift(gen);
+                    }
+                    bindings.set(gen.bindingName.name, gen.bindingName.generics);
                     return false;
                 }
                 return true;
@@ -658,6 +689,38 @@
         return end;
     }
 
+    function getFilteredNextElem(query, parserState, elems, isInGenerics) {
+        const start = parserState.pos;
+        if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
+            throw ["Expected type filter before ", ":"];
+        }
+        getNextElem(query, parserState, elems, isInGenerics);
+        if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
+            if (parserState.typeFilter !== null) {
+                throw [
+                    "Unexpected ",
+                    ":",
+                    " (expected path after type filter ",
+                    parserState.typeFilter + ":",
+                    ")",
+                ];
+            }
+            if (elems.length === 0) {
+                throw ["Expected type filter before ", ":"];
+            } else if (query.literalSearch) {
+                throw ["Cannot use quotes on type filter"];
+            }
+            // The type filter doesn't count as an element since it's a modifier.
+            const typeFilterElem = elems.pop();
+            checkExtraTypeFilterCharacters(start, parserState);
+            parserState.typeFilter = typeFilterElem.name;
+            parserState.pos += 1;
+            parserState.totalElems -= 1;
+            query.literalSearch = false;
+            getNextElem(query, parserState, elems, isInGenerics);
+        }
+    }
+
     /**
      * @param {ParsedQuery} query
      * @param {ParserState} parserState
@@ -671,28 +734,19 @@
         let start = parserState.pos;
         let end;
         if ("[(".indexOf(parserState.userQuery[parserState.pos]) !== -1) {
-let endChar = ")";
-let name = "()";
-let friendlyName = "tuple";
+            let endChar = ")";
+            let name = "()";
+            let friendlyName = "tuple";
 
-if (parserState.userQuery[parserState.pos] === "[") {
-    endChar = "]";
-    name = "[]";
-    friendlyName = "slice";
-}
+            if (parserState.userQuery[parserState.pos] === "[") {
+                endChar = "]";
+                name = "[]";
+                friendlyName = "slice";
+            }
             parserState.pos += 1;
             const { foundSeparator } = getItemsBefore(query, parserState, generics, endChar);
             const typeFilter = parserState.typeFilter;
-            const isInBinding = parserState.isInBinding;
-            if (typeFilter !== null && typeFilter !== "primitive") {
-                throw [
-                    "Invalid search type: primitive ",
-                    name,
-                    " and ",
-                    typeFilter,
-                    " both specified",
-                ];
-            }
+            const bindingName = parserState.isInBinding;
             parserState.typeFilter = null;
             parserState.isInBinding = null;
             for (const gen of generics) {
@@ -702,23 +756,26 @@
             }
             if (name === "()" && !foundSeparator && generics.length === 1 && typeFilter === null) {
                 elems.push(generics[0]);
+            } else if (name === "()" && generics.length === 1 && generics[0].name === "->") {
+                // `primitive:(a -> b)` parser to `primitive:"->"<output=b, (a,)>`
+                // not `primitive:"()"<"->"<output=b, (a,)>>`
+                generics[0].typeFilter = typeFilter;
+                elems.push(generics[0]);
             } else {
+                if (typeFilter !== null && typeFilter !== "primitive") {
+                    throw [
+                        "Invalid search type: primitive ",
+                        name,
+                        " and ",
+                        typeFilter,
+                        " both specified",
+                    ];
+                }
                 parserState.totalElems += 1;
                 if (isInGenerics) {
                     parserState.genericsElems += 1;
                 }
-                elems.push({
-                    name: name,
-                    id: null,
-                    fullPath: [name],
-                    pathWithoutLast: [],
-                    pathLast: name,
-                    normalizedPathLast: name,
-                    generics,
-                    bindings: new Map(),
-                    typeFilter: "primitive",
-                    bindingName: isInBinding,
-                });
+                elems.push(makePrimitiveElement(name, { bindingName, generics }));
             }
         } else {
             const isStringElem = parserState.userQuery[start] === "\"";
@@ -738,6 +795,32 @@
                 }
                 parserState.pos += 1;
                 getItemsBefore(query, parserState, generics, ">");
+            } else if (parserState.pos < parserState.length &&
+                parserState.userQuery[parserState.pos] === "("
+            ) {
+                if (start >= end) {
+                    throw ["Found generics without a path"];
+                }
+                if (parserState.isInBinding) {
+                    throw ["Unexpected ", "(", " after ", "="];
+                }
+                parserState.pos += 1;
+                const typeFilter = parserState.typeFilter;
+                parserState.typeFilter = null;
+                getItemsBefore(query, parserState, generics, ")");
+                skipWhitespace(parserState);
+                if (isReturnArrow(parserState)) {
+                    parserState.pos += 2;
+                    skipWhitespace(parserState);
+                    getFilteredNextElem(query, parserState, generics, isInGenerics);
+                    generics[generics.length - 1].bindingName = makePrimitiveElement("output");
+                } else {
+                    generics.push(makePrimitiveElement(null, {
+                        bindingName: makePrimitiveElement("output"),
+                        typeFilter: null,
+                    }));
+                }
+                parserState.typeFilter = typeFilter;
             }
             if (isStringElem) {
                 skipWhitespace(parserState);
@@ -797,7 +880,6 @@
     function getItemsBefore(query, parserState, elems, endChar) {
         let foundStopChar = true;
         let foundSeparator = false;
-        let start = parserState.pos;
 
         // If this is a generic, keep the outer item's type filter around.
         const oldTypeFilter = parserState.typeFilter;
@@ -805,6 +887,19 @@
         const oldIsInBinding = parserState.isInBinding;
         parserState.isInBinding = null;
 
+        // ML-style Higher Order Function notation
+        //
+        // a way to search for any closure or fn pointer regardless of
+        // which closure trait is used
+        //
+        // Looks like this:
+        //
+        //     `option<t>, (t -> u) -> option<u>`
+        //                  ^^^^^^
+        //
+        // The Rust-style closure notation is implemented in getNextElem
+        let hofParameters = null;
+
         let extra = "";
         if (endChar === ">") {
             extra = "<";
@@ -825,6 +920,21 @@
                     throw ["Unexpected ", endChar, " after ", "="];
                 }
                 break;
+            } else if (endChar !== "" && isReturnArrow(parserState)) {
+                // ML-style HOF notation only works when delimited in something,
+                // otherwise a function arrow starts the return type of the top
+                if (parserState.isInBinding) {
+                    throw ["Unexpected ", "->", " after ", "="];
+                }
+                hofParameters = [...elems];
+                elems.length = 0;
+                parserState.pos += 2;
+                foundStopChar = true;
+                foundSeparator = false;
+                continue;
+            } else if (c === " ") {
+                parserState.pos += 1;
+                continue;
             } else if (isSeparatorCharacter(c)) {
                 parserState.pos += 1;
                 foundStopChar = true;
@@ -832,24 +942,6 @@
                 continue;
             } else if (c === ":" && isPathStart(parserState)) {
                 throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
-            }  else if (c === ":") {
-                if (parserState.typeFilter !== null) {
-                    throw ["Unexpected ", ":"];
-                }
-                if (elems.length === 0) {
-                    throw ["Expected type filter before ", ":"];
-                } else if (query.literalSearch) {
-                    throw ["Cannot use quotes on type filter"];
-                }
-                // The type filter doesn't count as an element since it's a modifier.
-                const typeFilterElem = elems.pop();
-                checkExtraTypeFilterCharacters(start, parserState);
-                parserState.typeFilter = typeFilterElem.name;
-                parserState.pos += 1;
-                parserState.totalElems -= 1;
-                query.literalSearch = false;
-                foundStopChar = true;
-                continue;
             } else if (isEndCharacter(c)) {
                 throw ["Unexpected ", c, " after ", extra];
             }
@@ -884,8 +976,7 @@
                 ];
             }
             const posBefore = parserState.pos;
-            start = parserState.pos;
-            getNextElem(query, parserState, elems, endChar !== "");
+            getFilteredNextElem(query, parserState, elems, endChar !== "");
             if (endChar !== "" && parserState.pos >= parserState.length) {
                 throw ["Unclosed ", extra];
             }
@@ -904,6 +995,27 @@
         // in any case.
         parserState.pos += 1;
 
+        if (hofParameters) {
+            // Commas in a HOF don't cause wrapping parens to become a tuple.
+            // If you want a one-tuple with a HOF in it, write `((a -> b),)`.
+            foundSeparator = false;
+            // HOFs can't have directly nested bindings.
+            if ([...elems, ...hofParameters].some(x => x.bindingName) || parserState.isInBinding) {
+                throw ["Unexpected ", "=", " within ", "->"];
+            }
+            // HOFs are represented the same way closures are.
+            // The arguments are wrapped in a tuple, and the output
+            // is a binding, even though the compiler doesn't technically
+            // represent fn pointers that way.
+            const hofElem = makePrimitiveElement("->", {
+                generics: hofParameters,
+                bindings: new Map([["output", [...elems]]]),
+                typeFilter: null,
+            });
+            elems.length = 0;
+            elems[0] = hofElem;
+        }
+
         parserState.typeFilter = oldTypeFilter;
         parserState.isInBinding = oldIsInBinding;
 
@@ -941,7 +1053,6 @@
      */
     function parseInput(query, parserState) {
         let foundStopChar = true;
-        let start = parserState.pos;
 
         while (parserState.pos < parserState.length) {
             const c = parserState.userQuery[parserState.pos];
@@ -959,29 +1070,6 @@
                     throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]];
                 }
                 throw ["Unexpected ", c];
-            } else if (c === ":" && !isPathStart(parserState)) {
-                if (parserState.typeFilter !== null) {
-                    throw [
-                        "Unexpected ",
-                        ":",
-                        " (expected path after type filter ",
-                        parserState.typeFilter + ":",
-                        ")",
-                    ];
-                } else if (query.elems.length === 0) {
-                    throw ["Expected type filter before ", ":"];
-                } else if (query.literalSearch) {
-                    throw ["Cannot use quotes on type filter"];
-                }
-                // The type filter doesn't count as an element since it's a modifier.
-                const typeFilterElem = query.elems.pop();
-                checkExtraTypeFilterCharacters(start, parserState);
-                parserState.typeFilter = typeFilterElem.name;
-                parserState.pos += 1;
-                parserState.totalElems -= 1;
-                query.literalSearch = false;
-                foundStopChar = true;
-                continue;
             } else if (c === " ") {
                 skipWhitespace(parserState);
                 continue;
@@ -1017,8 +1105,7 @@
                 ];
             }
             const before = query.elems.length;
-            start = parserState.pos;
-            getNextElem(query, parserState, query.elems, false);
+            getFilteredNextElem(query, parserState, query.elems, false);
             if (query.elems.length === before) {
                 // Nothing was added, weird... Let's increase the position to not remain stuck.
                 parserState.pos += 1;
@@ -1258,11 +1345,6 @@
          * @returns {[ResultObject]}
          */
         function sortResults(results, isType, preferredCrate) {
-            // if there are no results then return to default and fail
-            if (results.size === 0) {
-                return [];
-            }
-
             const userQuery = parsedQuery.userQuery;
             const result_list = [];
             for (const result of results.values()) {
@@ -1383,10 +1465,23 @@
          * @param {Map<number,number>|null} mgensIn
          *     - Map functions generics to query generics (never modified).
          * @param {null|Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         * @param {number} unboxingDepth
+         *     - Limit checks that Ty matches Vec<Ty>,
+         *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
          *
          * @return {boolean} - Returns true if a match, false otherwise.
          */
-        function unifyFunctionTypes(fnTypesIn, queryElems, whereClause, mgensIn, solutionCb) {
+        function unifyFunctionTypes(
+            fnTypesIn,
+            queryElems,
+            whereClause,
+            mgensIn,
+            solutionCb,
+            unboxingDepth
+        ) {
+            if (unboxingDepth >= UNBOXING_LIMIT) {
+                return false;
+            }
             /**
              * @type Map<integer, integer>|null
              */
@@ -1405,7 +1500,7 @@
                 && queryElems[0].bindings.size === 0) {
                 const queryElem = queryElems[0];
                 for (const fnType of fnTypesIn) {
-                    if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
+                    if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
                         continue;
                     }
                     if (fnType.id < 0 && queryElem.id < 0) {
@@ -1424,7 +1519,13 @@
                     }
                 }
                 for (const fnType of fnTypesIn) {
-                    if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
+                    if (!unifyFunctionTypeIsUnboxCandidate(
+                        fnType,
+                        queryElem,
+                        whereClause,
+                        mgens,
+                        unboxingDepth + 1
+                    )) {
                         continue;
                     }
                     if (fnType.id < 0) {
@@ -1439,7 +1540,8 @@
                             queryElems,
                             whereClause,
                             mgensScratch,
-                            solutionCb
+                            solutionCb,
+                            unboxingDepth + 1
                         )) {
                             return true;
                         }
@@ -1448,7 +1550,8 @@
                         queryElems,
                         whereClause,
                         mgens ? new Map(mgens) : null,
-                        solutionCb
+                        solutionCb,
+                        unboxingDepth + 1
                     )) {
                         return true;
                     }
@@ -1484,7 +1587,7 @@
             let queryElemsTmp = null;
             for (let i = flast; i >= 0; i -= 1) {
                 const fnType = fnTypes[i];
-                if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgens)) {
+                if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
                     continue;
                 }
                 let mgensScratch;
@@ -1521,7 +1624,8 @@
                             fnType,
                             queryElem,
                             whereClause,
-                            mgensScratch
+                            mgensScratch,
+                            unboxingDepth
                         );
                         if (!solution) {
                             return false;
@@ -1533,14 +1637,16 @@
                                 queryElem.generics,
                                 whereClause,
                                 simplifiedMgens,
-                                solutionCb
+                                solutionCb,
+                                unboxingDepth
                             );
                             if (passesUnification) {
                                 return true;
                             }
                         }
                         return false;
-                    }
+                    },
+                    unboxingDepth
                 );
                 if (passesUnification) {
                     return true;
@@ -1552,7 +1658,13 @@
             }
             for (let i = flast; i >= 0; i -= 1) {
                 const fnType = fnTypes[i];
-                if (!unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens)) {
+                if (!unifyFunctionTypeIsUnboxCandidate(
+                    fnType,
+                    queryElem,
+                    whereClause,
+                    mgens,
+                    unboxingDepth + 1
+                )) {
                     continue;
                 }
                 let mgensScratch;
@@ -1576,7 +1688,8 @@
                     queryElems,
                     whereClause,
                     mgensScratch,
-                    solutionCb
+                    solutionCb,
+                    unboxingDepth + 1
                 );
                 if (passesUnification) {
                     return true;
@@ -1595,11 +1708,10 @@
          *
          * @param {FunctionType} fnType
          * @param {QueryElement} queryElem
-         * @param {[FunctionSearchType]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn - Map functions generics to query generics.
          * @returns {boolean}
          */
-        function unifyFunctionTypeIsMatchCandidate(fnType, queryElem, whereClause, mgensIn) {
+        function unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgensIn) {
             // type filters look like `trait:Read` or `enum:Result`
             if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
                 return false;
@@ -1635,6 +1747,12 @@
                 ) {
                     // () matches primitive:tuple or primitive:unit
                     // if it matches, then we're fine, and this is an appropriate match candidate
+                } else if (queryElem.id === typeNameIdOfHof &&
+                    (fnType.id === typeNameIdOfFn || fnType.id === typeNameIdOfFnMut ||
+                        fnType.id === typeNameIdOfFnOnce)
+                ) {
+                    // -> matches fn, fnonce, and fnmut
+                    // if it matches, then we're fine, and this is an appropriate match candidate
                 } else if (fnType.id !== queryElem.id || queryElem.id === null) {
                     return false;
                 }
@@ -1694,9 +1812,16 @@
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>} mgensIn - Map functions generics to query generics.
          *                                            Never modified.
+         * @param {number} unboxingDepth
          * @returns {false|{mgens: [Map<number,number>], simplifiedGenerics: [FunctionType]}}
          */
-        function unifyFunctionTypeCheckBindings(fnType, queryElem, whereClause, mgensIn) {
+        function unifyFunctionTypeCheckBindings(
+            fnType,
+            queryElem,
+            whereClause,
+            mgensIn,
+            unboxingDepth
+        ) {
             if (fnType.bindings.size < queryElem.bindings.size) {
                 return false;
             }
@@ -1723,7 +1848,8 @@
                                 // return `false` makes unifyFunctionTypes return the full set of
                                 // possible solutions
                                 return false;
-                            }
+                            },
+                            unboxingDepth
                         );
                         return newSolutions;
                     });
@@ -1753,9 +1879,19 @@
          * @param {QueryElement} queryElem
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
+         * @param {number} unboxingDepth
          * @returns {boolean}
          */
-        function unifyFunctionTypeIsUnboxCandidate(fnType, queryElem, whereClause, mgens) {
+        function unifyFunctionTypeIsUnboxCandidate(
+            fnType,
+            queryElem,
+            whereClause,
+            mgens,
+            unboxingDepth
+        ) {
+            if (unboxingDepth >= UNBOXING_LIMIT) {
+                return false;
+            }
             if (fnType.id < 0 && queryElem.id >= 0) {
                 if (!whereClause) {
                     return false;
@@ -1777,14 +1913,21 @@
                     whereClause[(-fnType.id) - 1],
                     queryElem,
                     whereClause,
-                    mgensTmp
+                    mgensTmp,
+                    unboxingDepth
                 );
             } else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
                 const simplifiedGenerics = [
                     ...fnType.generics,
                     ...Array.from(fnType.bindings.values()).flat(),
                 ];
-                return checkIfInList(simplifiedGenerics, queryElem, whereClause, mgens);
+                return checkIfInList(
+                    simplifiedGenerics,
+                    queryElem,
+                    whereClause,
+                    mgens,
+                    unboxingDepth
+                );
             }
             return false;
         }
@@ -1796,13 +1939,14 @@
           * @param {Array<FunctionType>} list
           * @param {QueryElement} elem          - The element from the parsed query.
           * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
+          * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
+          * @param {number} unboxingDepth
           *
           * @return {boolean} - Returns true if found, false otherwise.
           */
-        function checkIfInList(list, elem, whereClause, mgens) {
+        function checkIfInList(list, elem, whereClause, mgens, unboxingDepth) {
             for (const entry of list) {
-                if (checkType(entry, elem, whereClause, mgens)) {
+                if (checkType(entry, elem, whereClause, mgens, unboxingDepth)) {
                     return true;
                 }
             }
@@ -1816,29 +1960,40 @@
           * @param {Row} row
           * @param {QueryElement} elem          - The element from the parsed query.
           * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
+          * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
           *
           * @return {boolean} - Returns true if the type matches, false otherwise.
           */
-        function checkType(row, elem, whereClause, mgens) {
+        function checkType(row, elem, whereClause, mgens, unboxingDepth) {
+            if (unboxingDepth >= UNBOXING_LIMIT) {
+                return false;
+            }
             if (row.bindings.size === 0 && elem.bindings.size === 0) {
-                if (elem.id < 0) {
-                    return row.id < 0 || checkIfInList(row.generics, elem, whereClause, mgens);
+                if (elem.id < 0 && mgens === null) {
+                    return row.id < 0 || checkIfInList(
+                        row.generics,
+                        elem,
+                        whereClause,
+                        mgens,
+                        unboxingDepth + 1
+                    );
                 }
                 if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
                     typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
                     // special case
                     elem.id !== typeNameIdOfArrayOrSlice && elem.id !== typeNameIdOfTupleOrUnit
+                    && elem.id !== typeNameIdOfHof
                 ) {
                     return row.id === elem.id || checkIfInList(
                         row.generics,
                         elem,
                         whereClause,
-                        mgens
+                        mgens,
+                        unboxingDepth
                     );
                 }
             }
-            return unifyFunctionTypes([row], [elem], whereClause, mgens);
+            return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth);
         }
 
         /**
@@ -2053,9 +2208,9 @@
             );
             if (tfpDist !== null) {
                 const in_args = row.type && row.type.inputs
-                    && checkIfInList(row.type.inputs, elem, row.type.where_clause);
+                    && checkIfInList(row.type.inputs, elem, row.type.where_clause, null, 0);
                 const returned = row.type && row.type.output
-                    && checkIfInList(row.type.output, elem, row.type.where_clause);
+                    && checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
                 if (in_args) {
                     results_in_args.max_dist = Math.max(results_in_args.max_dist || 0, tfpDist);
                     const maxDist = results_in_args.size < MAX_RESULTS ?
@@ -2141,9 +2296,12 @@
                         row.type.output,
                         parsedQuery.returned,
                         row.type.where_clause,
-                        mgens
+                        mgens,
+                        null,
+                        0 // unboxing depth
                     );
-                }
+                },
+                0 // unboxing depth
             )) {
                 return;
             }
@@ -2991,7 +3149,7 @@
      */
     function buildFunctionTypeFingerprint(type, output, fps) {
         let input = type.id;
-        // All forms of `[]`/`()` get collapsed down to one thing in the bloom filter.
+        // All forms of `[]`/`()`/`->` get collapsed down to one thing in the bloom filter.
         // Differentiating between arrays and slices, if the user asks for it, is
         // still done in the matching algorithm.
         if (input === typeNameIdOfArray || input === typeNameIdOfSlice) {
@@ -3000,6 +3158,10 @@
         if (input === typeNameIdOfTuple || input === typeNameIdOfUnit) {
             input = typeNameIdOfTupleOrUnit;
         }
+        if (input === typeNameIdOfFn || input === typeNameIdOfFnMut ||
+            input === typeNameIdOfFnOnce) {
+            input = typeNameIdOfHof;
+        }
         // http://burtleburtle.net/bob/hash/integer.html
         // ~~ is toInt32. It's used before adding, so
         // the number stays in safe integer range.
@@ -3090,20 +3252,10 @@
      */
     function buildIndex(rawSearchIndex) {
         searchIndex = [];
-        typeNameIdMap = new Map();
         const charA = "A".charCodeAt(0);
         let currentIndex = 0;
         let id = 0;
 
-        // Initialize type map indexes for primitive list types
-        // that can be searched using `[]` syntax.
-        typeNameIdOfArray = buildTypeMapIndex("array");
-        typeNameIdOfSlice = buildTypeMapIndex("slice");
-        typeNameIdOfTuple = buildTypeMapIndex("tuple");
-        typeNameIdOfUnit = buildTypeMapIndex("unit");
-        typeNameIdOfArrayOrSlice = buildTypeMapIndex("[]");
-        typeNameIdOfTupleOrUnit = buildTypeMapIndex("()");
-
         // Function type fingerprints are 128-bit bloom filters that are used to
         // estimate the distance between function and query.
         // This loop counts the number of items to allocate a fingerprint for.
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 39d27b1..1865187 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -530,6 +530,14 @@
         unstable("test-builder", |o| {
             o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
         }),
+        unstable("test-builder-wrapper", |o| {
+            o.optmulti(
+                "",
+                "test-builder-wrapper",
+                "Wrapper program to pass test-builder and arguments",
+                "PATH",
+            )
+        }),
         unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")),
         unstable("generate-redirect-map", |o| {
             o.optflagmulti(
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 0603aae..e85b998 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -80,9 +80,8 @@
 
     // check if parent is trait impl
     if let Some(parent_def_id) = cx.tcx.opt_local_parent(def_id)
-        && let Some(parent_node) = cx.tcx.opt_hir_node_by_def_id(parent_def_id)
         && matches!(
-            parent_node,
+            cx.tcx.hir_node_by_def_id(parent_def_id),
             hir::Node::Item(hir::Item {
                 kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }),
                 ..
diff --git a/src/llvm-project b/src/llvm-project
index 7973f35..84f190a 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 7973f3560287d750500718314a0fd4025bd8ac0e
+Subproject commit 84f190a4abf58bbd5301c0fc831f7a96acea246f
diff --git a/src/tools/cargo b/src/tools/cargo
index 7065f0e..2fe739f 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 7065f0ef4aa267a7455e1c478b5ccacb7baea59c
+Subproject commit 2fe739fcf16c5bf8c2064ab9d357f4a0e6c8539b
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index 9b36cc0..91ae19a 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -52,7 +52,7 @@
             .as_ref()
             .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)),
         |stmt| match &stmt.kind {
-            StmtKind::Local(_) => true,
+            StmtKind::Let(_) => true,
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
             StmtKind::Item(_) => false,
         },
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 247048b..acdcb54 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -349,7 +349,7 @@
 
 /// If the statement is a local, checks if the bound names match the expected list of names.
 fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool {
-    if let StmtKind::Local(l) = s.kind {
+    if let StmtKind::Let(l) = s.kind {
         let mut i = 0usize;
         let mut res = true;
         l.pat.each_binding_or_first(&mut |_, _, _, name| {
@@ -389,7 +389,7 @@
     eq: &mut HirEqInterExpr<'_, '_, '_>,
     moved_bindings: &mut Vec<(HirId, Symbol)>,
 ) -> bool {
-    (if let StmtKind::Local(l) = stmt.kind {
+    (if let StmtKind::Let(l) = stmt.kind {
         let old_count = moved_bindings.len();
         l.pat.each_binding_or_first(&mut |_, id, _, name| {
             moved_bindings.push((id, name.name));
@@ -432,7 +432,7 @@
         .iter()
         .enumerate()
         .find(|&(i, stmt)| {
-            if let StmtKind::Local(l) = stmt.kind
+            if let StmtKind::Let(l) = stmt.kind
                 && needs_ordered_drop(cx, cx.typeck_results().node_type(l.hir_id))
             {
                 local_needs_ordered_drop = true;
@@ -509,7 +509,7 @@
                 // Clear out all locals seen at the end so far. None of them can be moved.
                 let stmts = &blocks[0].stmts;
                 for stmt in &stmts[stmts.len() - init..=stmts.len() - offset] {
-                    if let StmtKind::Local(l) = stmt.kind {
+                    if let StmtKind::Let(l) = stmt.kind {
                         l.pat.each_binding_or_first(&mut |_, id, _, _| {
                             // FIXME(rust/#120456) - is `swap_remove` correct?
                             eq.locals.swap_remove(&id);
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 8789efc..98a6d93 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -121,7 +121,7 @@
             // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
             // `default` method of the `Default` trait, and store statement index in current block being
             // checked and the name of the bound variable
-            let (local, variant, binding_name, binding_type, span) = if let StmtKind::Local(local) = stmt.kind
+            let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind
                 // only take `let ...` statements
                 && let Some(expr) = local.init
                 && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 59d2df0..1d6c4ce 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -221,7 +221,7 @@
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
             // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
-            StmtKind::Local(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())),
+            StmtKind::Let(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())),
 
             _ => self.ty_bounds.push(ExplicitTyBound(false)),
         }
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index de6073c..ebda2ad 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -423,7 +423,7 @@
                 }
             },
             StmtKind::Expr(e) => self.visit_expr(e),
-            StmtKind::Local(l) => {
+            StmtKind::Let(l) => {
                 self.visit_pat(l.pat);
                 if let Some(e) = l.init {
                     self.allow_insert_closure &= !self.in_tail_pos;
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 8857cb8..ad589da 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -76,10 +76,9 @@
             .hir()
             .get_parent_item(cx.tcx.local_def_id_to_hir_id(fn_def_id))
             .def_id;
-        let parent_node = cx.tcx.opt_hir_node_by_def_id(parent_id);
 
         let mut trait_self_ty = None;
-        if let Some(Node::Item(item)) = parent_node {
+        if let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_id) {
             // If the method is an impl for a trait, don't warn.
             if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = item.kind {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 6603512..106844d 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -46,7 +46,7 @@
             && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::process_exit, def_id)
             && let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id
-            && let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.opt_hir_node_by_def_id(parent)
+            && let Node::Item(Item{kind: ItemKind::Fn(..), ..}) = cx.tcx.hir_node_by_def_id(parent)
             // If the next item up is a function we check if it is an entry point
             // and only then emit a linter warning
             && !is_entrypoint_fn(cx, parent.to_def_id())
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index de048fe..2e9bec6 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -102,7 +102,7 @@
 fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) -> &'tcx ExprKind<'hir> {
     if let ExprKind::Block(block, _label @ None) = kind
         && let Block {
-            stmts: [Stmt { kind: StmtKind::Local(local), .. }],
+            stmts: [Stmt { kind: StmtKind::Let(local), .. }],
             expr: Some(expr_end_of_block),
             rules: BlockCheckMode::DefaultBlock,
             ..
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 7f36f33..37fbf2c 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -92,7 +92,7 @@
             .expect("already checked this is adt")
             .did()
             .as_local()
-        && let Some(hir::Node::Item(item)) = cx.tcx.opt_hir_node_by_def_id(local_def_id)
+        && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id)
         && let hir::ItemKind::Enum(ref def, _) = item.kind
     {
         let variants_size = AdtVariantInfo::new(cx, *adt, subst);
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 270162a..f084d89 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -61,7 +61,7 @@
         let mut it = block.stmts.iter().peekable();
         while let Some(stmt) = it.next() {
             if let Some(expr) = it.peek()
-                && let hir::StmtKind::Local(local) = stmt.kind
+                && let hir::StmtKind::Let(local) = stmt.kind
                 && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
                 && let hir::StmtKind::Expr(if_) = expr.kind
                 && let hir::ExprKind::If(
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index 18f799e..a7c1d1b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -410,7 +410,7 @@
     stmts
         .iter()
         .filter_map(move |stmt| match stmt.kind {
-            StmtKind::Local(..) | StmtKind::Item(..) => None,
+            StmtKind::Let(..) | StmtKind::Item(..) => None,
             StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
         })
         .chain(*expr)
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
index ca584a4..b00a082 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -72,7 +72,7 @@
 }
 
 fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
-    if let StmtKind::Local(local) = stmt.kind
+    if let StmtKind::Let(local) = stmt.kind
         && let Some(init) = local.init
         && is_vec_pop_unwrap(cx, init, is_empty_recv)
     {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 65d922f..6cc7944 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -137,7 +137,7 @@
     match stmt.kind {
         StmtKind::Semi(e) | StmtKind::Expr(e) => Some((e, None)),
         // add the let...else expression (if present)
-        StmtKind::Local(local) => local.init.map(|init| (init, local.els)),
+        StmtKind::Let(local) => local.init.map(|init| (init, local.els)),
         StmtKind::Item(..) => None,
     }
 }
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 735d704..93774b8 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 @@
 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 {
+            if let StmtKind::Let(&Local {
                 init: Some(e),
                 els: None,
                 ..
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index fdf8fa4..03e4d66 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -53,7 +53,7 @@
             return;
         }
 
-        if let StmtKind::Local(local) = stmt.kind
+        if let StmtKind::Let(local) = stmt.kind
             && let Some(init) = local.init
             && local.els.is_none()
             && local.ty.is_none()
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 3b82c50..c9eab71 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -138,7 +138,7 @@
                     // If block only contains statements,
                     // reduce `{ X; }` to `X` or `X;`
                     match inner_stmt.kind {
-                        hir::StmtKind::Local(local) => Some(local.span),
+                        hir::StmtKind::Let(local) => Some(local.span),
                         hir::StmtKind::Expr(e) => Some(e.span),
                         hir::StmtKind::Semi(..) => Some(inner_stmt.span),
                         hir::StmtKind::Item(..) => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 55050ae..7854035 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -424,7 +424,7 @@
     match stmt.kind {
         StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)),
         StmtKind::Item(..) => None,
-        StmtKind::Local(Local { init, pat, .. }) => {
+        StmtKind::Let(Local { init, pat, .. }) => {
             if let PatKind::Binding(_, hir_id, ..) = pat.kind {
                 init.map(|init_expr| (init_expr, Some(hir_id)))
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 0e7ad8f..55cd1a3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -198,7 +198,7 @@
     binding: HirId,
     ctxt: SyntaxContext,
 ) -> Option<IndirectUsage<'tcx>> {
-    if let StmtKind::Local(&Local {
+    if let StmtKind::Let(&Local {
         pat: Pat {
             kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
             ..
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
index 7b0cf48..cdfaa69 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
@@ -27,7 +27,7 @@
 
 fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option<HirId> {
     for stmt in statements {
-        if let StmtKind::Local(local) = stmt.kind
+        if let StmtKind::Let(local) = stmt.kind
             && let Some(init) = local.init
             && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind
             && let hir::def::Res::Local(local_hir_id) = path.res
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index b9784a5..ea6e662 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -143,7 +143,7 @@
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if !in_external_macro(cx.tcx.sess, stmt.span)
-            && let StmtKind::Local(local) = stmt.kind
+            && let StmtKind::Let(local) = stmt.kind
             && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind
             && let Some(init) = local.init
             // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
@@ -225,10 +225,9 @@
                 if let Some(adt_def) = cx.typeck_results().expr_ty_adjusted(recv).ty_adt_def()
                     && let Some(field) = adt_def.all_fields().find(|field| field.name == ident.name)
                     && let Some(local_did) = field.did.as_local()
-                    && let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(local_did)
                     && !cx.tcx.type_of(field.did).skip_binder().is_phantom_data()
                 {
-                    (hir_id, ident)
+                    (cx.tcx.local_def_id_to_hir_id(local_did), ident)
                 } else {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 88b331d..3bf9f75 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -220,7 +220,7 @@
             && let self_ty = cx.tcx.type_of(self_path_did).skip_binder().peel_refs()
             && let Some(self_adt) = self_ty.ty_adt_def()
             && let Some(self_def_id) = self_adt.did().as_local()
-            && let Some(Node::Item(self_item)) = cx.tcx.opt_hir_node_by_def_id(self_def_id)
+            && let Node::Item(self_item) = cx.tcx.hir_node_by_def_id(self_def_id)
             // NB: can't call cx.typeck_results() as we are not in a body
             && let typeck_results = cx.tcx.typeck_body(*body_id)
             && should_lint(cx, typeck_results, block)
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index a1f7dc7..12c7c18 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -97,7 +97,7 @@
     }
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
-            StmtKind::Local(local) => {
+            StmtKind::Let(local) => {
                 if let Local { init: Some(e), .. } = local {
                     DivergenceVisitor { cx }.visit_expr(e);
                 }
@@ -291,7 +291,7 @@
         StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
         // If the declaration is of a local variable, check its initializer
         // expression if it has one. Otherwise, keep going.
-        StmtKind::Local(local) => local
+        StmtKind::Let(local) => local
             .init
             .as_ref()
             .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 3e63c0a..4cda4b1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -86,7 +86,7 @@
 }
 
 fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
-    let StmtKind::Local(local) = stmt.kind else {
+    let StmtKind::Let(local) = stmt.kind else {
         return false;
     };
     !local.pat.walk_short(|pat| {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index a5b58f9..a450dee 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -112,10 +112,7 @@
         }
         ctx.prev_bind = None;
         ctx.prev_move_to_closure.clear();
-        if let Some(body) = cx
-            .tcx
-            .opt_hir_node_by_def_id(closure)
-            .and_then(associated_body)
+        if let Some(body) = associated_body(cx.tcx.hir_node_by_def_id(closure))
             .map(|(_, body_id)| hir.body(body_id))
         {
             euv::ExprUseVisitor::new(ctx, infcx, closure, cx.param_env, cx.typeck_results()).consume_body(body);
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index cac34c8..43810ec 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -174,7 +174,7 @@
                 );
                 return true;
             }
-        } else if let StmtKind::Local(local) = stmt.kind {
+        } else if let StmtKind::Let(local) = stmt.kind {
             if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id)
                 && !matches!(local.source, LocalSource::AsyncFn)
                 && let Some(init) = local.init
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 60ced9c..fbca432 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -82,7 +82,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if let StmtKind::Local(local) = stmt.kind {
+        if let StmtKind::Let(local) = stmt.kind {
             if in_external_macro(cx.sess(), local.pat.span) {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index cf7f7301..831c291 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -109,7 +109,7 @@
 }
 
 fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
-    if let StmtKind::Local(Local {
+    if let StmtKind::Let(Local {
         pat,
         init: Some(init_expr),
         els: Some(els),
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 650324d..d0b37cd 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -56,7 +56,7 @@
                 return;
             }
 
-            if let StmtKind::Local(local) = stmt.kind
+            if let StmtKind::Let(local) = stmt.kind
                 && let Local {
                     pat, init: Some(init), ..
                 } = local
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index f61527c..c2673bc 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -262,7 +262,7 @@
         }
 
         for w in block.stmts.windows(2) {
-            if let hir::StmtKind::Local(local) = w[0].kind
+            if let hir::StmtKind::Let(local) = w[0].kind
                 && let Option::Some(t) = local.init
                 && let hir::ExprKind::Closure { .. } = t.kind
                 && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 2af466d..1969752 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -222,7 +222,7 @@
         // we need both a let-binding stmt and an expr
         if let Some(retexpr) = block.expr
             && let Some(stmt) = block.stmts.iter().last()
-            && let StmtKind::Local(local) = &stmt.kind
+            && let StmtKind::Let(local) = &stmt.kind
             && local.ty.is_none()
             && cx.tcx.hir().attrs(local.hir_id).is_empty()
             && let Some(initexpr) = &local.init
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index fc5a45d..85a2b1a 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -72,8 +72,7 @@
 
         if let Some(self_def) = self_ty.ty_adt_def()
             && let Some(self_local_did) = self_def.did().as_local()
-            && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did)
-            && let Node::Item(x) = cx.tcx.hir_node(self_id)
+            && let Node::Item(x) = cx.tcx.hir_node_by_def_id(self_local_did)
             && let type_name = x.ident.name.as_str().to_lowercase()
             && (impl_item.ident.name.as_str() == type_name
                 || impl_item.ident.name.as_str().replace('_', "") == type_name)
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 6c99ccd..f8726aa 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -236,7 +236,7 @@
     fn manage_has_expensive_expr_after_last_attr(&mut self) {
         let has_expensive_stmt = match self.ap.curr_stmt.kind {
             hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false,
-            hir::StmtKind::Local(local)
+            hir::StmtKind::Let(local)
                 if let Some(expr) = local.init
                     && let hir::ExprKind::Path(_) = expr.kind =>
             {
@@ -290,7 +290,7 @@
         };
         let mut ac = AttrChecker::new(self.cx, self.seen_types, self.type_cache);
         if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) {
-            if let hir::StmtKind::Local(local) = self.ap.curr_stmt.kind
+            if let hir::StmtKind::Let(local) = self.ap.curr_stmt.kind
                 && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
                 && !self.ap.apas.contains_key(&hir_id)
                 && {
@@ -326,7 +326,7 @@
                     return;
                 };
                 match self.ap.curr_stmt.kind {
-                    hir::StmtKind::Local(local) => {
+                    hir::StmtKind::Let(local) => {
                         if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
                             apa.last_bind_ident = ident;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
index 223cbb3..2ce7e71 100644
--- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
@@ -95,7 +95,7 @@
 /// to be considered.
 fn is_valid_item_kind(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
     matches!(
-        cx.tcx.hir_node(cx.tcx.local_def_id_to_hir_id(def_id)),
+        cx.tcx.hir_node_by_def_id(def_id),
         Node::Item(_) | Node::ImplItem(_) | Node::TraitItem(_)
     )
 }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 4837f28..ff8e8fe 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -119,7 +119,7 @@
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
         // or `Vec::new()`
-        if let StmtKind::Local(local) = stmt.kind
+        if let StmtKind::Let(local) = stmt.kind
             && let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind
             && let Some(init) = local.init
             && let Some(size_expr) = Self::as_vec_initializer(cx, init)
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index daa6fe8..be590ae 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -148,7 +148,7 @@
     }
 
     for [s1, s2, s3] in block.stmts.array_windows::<3>() {
-        if let StmtKind::Local(tmp) = s1.kind
+        if let StmtKind::Let(tmp) = s1.kind
             // let t = foo();
             && let Some(tmp_init) = tmp.init
             && let PatKind::Binding(.., ident, None) = tmp.pat.kind
@@ -243,7 +243,7 @@
         if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
             return Some((ExprOrIdent::Expr(lhs), rhs));
         }
-    } else if let StmtKind::Local(expr) = stmt.kind {
+    } else if let StmtKind::Let(expr) = stmt.kind {
         if let Some(rhs) = expr.init {
             if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind {
                 return Some((ExprOrIdent::Ident(ident_l), rhs));
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 7882bfd..bdef82e 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -321,7 +321,7 @@
         _: Span,
         def_id: LocalDefId,
     ) {
-        let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.opt_hir_node_by_def_id(
+        let is_in_trait_impl = if let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(
             cx.tcx
                 .hir()
                 .get_parent_item(cx.tcx.local_def_id_to_hir_id(def_id))
@@ -366,9 +366,9 @@
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
         match item.kind {
             ImplItemKind::Const(ty, _) => {
-                let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx
+                let is_in_trait_impl = if let hir::Node::Item(item) = cx
                     .tcx
-                    .opt_hir_node_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id)
+                    .hir_node_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id)
                 {
                     matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 559d7ac..0efa65b 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -158,7 +158,7 @@
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
-        let (hir::StmtKind::Local(&hir::Local { init: Some(expr), .. })
+        let (hir::StmtKind::Let(&hir::Local { init: Some(expr), .. })
         | hir::StmtKind::Expr(expr)
         | hir::StmtKind::Semi(expr)) = stmt.kind
         else {
@@ -358,7 +358,7 @@
         },
         Node::Stmt(hir::Stmt {
             kind:
-                hir::StmtKind::Local(hir::Local { span, hir_id, .. })
+                hir::StmtKind::Let(hir::Local { span, hir_id, .. })
                 | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. })
                 | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
             ..
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index fc8519d..9ffcfcc 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -153,7 +153,7 @@
 /// or `self` expression for `Vec::reserve()`.
 fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
     match stmt.kind {
-        StmtKind::Local(local) => {
+        StmtKind::Let(local) => {
             if let Some(init_expr) = local.init
                 && let PatKind::Binding(_, hir_id, _, None) = local.pat.kind
                 && let Some(init_kind) = get_vec_init_kind(cx, init_expr)
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 6b3ea77..eb64dd6 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -61,10 +61,10 @@
     ///   we need to check them at `check_expr` or `check_block` as they are not stmts
     ///   but we can't check them at `check_expr` because we need the broader context
     ///   because we should do this only for the final expression of the block, and not for
-    ///   `StmtKind::Local` which binds values => the io amount is used.
+    ///   `StmtKind::Let` which binds values => the io amount is used.
     ///
     /// To check for unused io amount in stmts, we only consider `StmtKind::Semi`.
-    /// `StmtKind::Local` is not considered because it binds values => the io amount is used.
+    /// `StmtKind::Let` is not considered because it binds values => the io amount is used.
     /// `StmtKind::Expr` is not considered because requires unit type => the io amount is used.
     /// `StmtKind::Item` is not considered because it's not an expression.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index ba72b34..f1d0c22 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -56,7 +56,7 @@
 
         for (idx, stmt) in block.stmts.iter().enumerate() {
             if !stmt.span.from_expansion()
-                && let StmtKind::Local(local) = stmt.kind
+                && let StmtKind::Let(local) = stmt.kind
                 && let PatKind::Binding(_, binding, ident, _) = local.pat.kind
                 && let Some(init) = local.init
                 && !init.span.from_expansion()
@@ -197,7 +197,7 @@
                     },
                     Node::Stmt(stmt) => {
                         match stmt.kind {
-                            StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true,
+                            StmtKind::Let(_) | StmtKind::Item(_) => self.found_peek_call = true,
                             StmtKind::Expr(_) | StmtKind::Semi(_) => {},
                         }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index a0a6382..187bfda 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -724,7 +724,7 @@
         }
 
         match stmt.value.kind {
-            StmtKind::Local(local) => {
+            StmtKind::Let(local) => {
                 bind!(self, local);
                 kind!("Local({local})");
                 self.option(field!(local.init), "init", |init| {
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 81d4a26..4aaf3b0 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -74,7 +74,7 @@
 fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let parent_id = cx.tcx.hir().get_parent_item(hir_id);
     let second_parent_id = cx.tcx.hir().get_parent_item(parent_id.into()).def_id;
-    if let Some(Node::Item(item)) = cx.tcx.opt_hir_node_by_def_id(second_parent_id) {
+    if let Node::Item(item) = cx.tcx.hir_node_by_def_id(second_parent_id) {
         if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
             return true;
         }
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 3b3939d..3874c11 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -267,7 +267,7 @@
 pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
     use StmtKind::*;
     match (&l.kind, &r.kind) {
-        (Local(l), Local(r)) => {
+        (Let(l), Let(r)) => {
             eq_pat(&l.pat, &r.pat)
                 && both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
                 && eq_local_kind(&l.kind, &r.kind)
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index f7f5f7c..106d1d0 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -108,7 +108,7 @@
 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::Let(l), &StmtKind::Let(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 {
@@ -1030,7 +1030,7 @@
         std::mem::discriminant(&b.kind).hash(&mut self.s);
 
         match &b.kind {
-            StmtKind::Local(local) => {
+            StmtKind::Let(local) => {
                 self.hash_pat(local.pat);
                 if let Some(init) = local.init {
                     self.hash_expr(init);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 708037a..a38db0e 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -330,8 +330,7 @@
 
 /// Checks if the `def_id` belongs to a function that is part of a trait impl.
 pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
-    if let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(def_id)
-        && let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
+    if let Node::Item(item) = cx.tcx.parent_hir_node(cx.tcx.local_def_id_to_hir_id(def_id))
         && let ItemKind::Impl(imp) = item.kind
     {
         imp.of_trait.is_some()
@@ -574,12 +573,12 @@
     let hir = tcx.hir();
 
     let root_mod;
-    let item_kind = match tcx.opt_hir_node_by_def_id(local_id) {
-        Some(Node::Crate(r#mod)) => {
+    let item_kind = match tcx.hir_node_by_def_id(local_id) {
+        Node::Crate(r#mod) => {
             root_mod = ItemKind::Mod(r#mod);
             &root_mod
         },
-        Some(Node::Item(item)) => &item.kind,
+        Node::Item(item) => &item.kind,
         _ => return Vec::new(),
     };
 
@@ -1254,12 +1253,10 @@
 /// Gets the name of the item the expression is in, if available.
 pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
-    match cx.tcx.opt_hir_node_by_def_id(parent_id) {
-        Some(
-            Node::Item(Item { ident, .. })
-            | Node::TraitItem(TraitItem { ident, .. })
-            | Node::ImplItem(ImplItem { ident, .. }),
-        ) => Some(ident.name),
+    match cx.tcx.hir_node_by_def_id(parent_id) {
+        Node::Item(Item { ident, .. })
+        | Node::TraitItem(TraitItem { ident, .. })
+        | Node::ImplItem(ImplItem { ident, .. }) => Some(ident.name),
         _ => None,
     }
 }
@@ -2161,7 +2158,7 @@
             Node::Stmt(Stmt {
                 kind: StmtKind::Expr(_)
                     | StmtKind::Semi(_)
-                    | StmtKind::Local(Local {
+                    | StmtKind::Let(Local {
                         pat: Pat {
                             kind: PatKind::Wild,
                             ..
@@ -2667,11 +2664,10 @@
                     .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
             )),
             Self::Return(id) => {
-                let hir_id = cx.tcx.local_def_id_to_hir_id(id.def_id);
                 if let Node::Expr(Expr {
                     kind: ExprKind::Closure(c),
                     ..
-                }) = cx.tcx.hir_node(hir_id)
+                }) = cx.tcx.hir_node_by_def_id(id.def_id)
                 {
                     match c.fn_decl.output {
                         FnRetTy::DefaultReturn(_) => None,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 6965822..a512599 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -852,6 +852,7 @@
     "only-sparc64",
     "only-stable",
     "only-thumb",
+    "only-unix",
     "only-wasm32",
     "only-wasm32-bare",
     "only-windows",
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 433f3e8..cf300fb 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -285,6 +285,7 @@
     assert!(check_ignore(&config, "//@ ignore-x86_64-unknown-linux-gnu"));
     assert!(check_ignore(&config, "//@ ignore-x86_64"));
     assert!(check_ignore(&config, "//@ ignore-linux"));
+    assert!(check_ignore(&config, "//@ ignore-unix"));
     assert!(check_ignore(&config, "//@ ignore-gnu"));
     assert!(check_ignore(&config, "//@ ignore-64bit"));
 
@@ -300,6 +301,7 @@
 
     assert!(check_ignore(&config, "//@ only-x86"));
     assert!(check_ignore(&config, "//@ only-linux"));
+    assert!(check_ignore(&config, "//@ only-unix"));
     assert!(check_ignore(&config, "//@ only-msvc"));
     assert!(check_ignore(&config, "//@ only-32bit"));
 
diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml
index d8a7a06..9ea26de 100644
--- a/src/tools/generate-windows-sys/Cargo.toml
+++ b/src/tools/generate-windows-sys/Cargo.toml
@@ -4,4 +4,4 @@
 edition = "2021"
 
 [dependencies.windows-bindgen]
-version = "0.52.0"
+version = "0.55.0"
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 49ed7ff..c70005c 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -165,7 +165,7 @@
           ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
         run: |
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
-            --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
+            --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \
             --message 'Dear @*T-miri*,
 
           It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed.
diff --git a/src/tools/miri/.github/workflows/sysroots.yml b/src/tools/miri/.github/workflows/sysroots.yml
index 96d7d4d..73a1076 100644
--- a/src/tools/miri/.github/workflows/sysroots.yml
+++ b/src/tools/miri/.github/workflows/sysroots.yml
@@ -21,6 +21,13 @@
           ./miri install
           python3 -m pip install beautifulsoup4
           ./ci/build-all-targets.sh
+      - name: Upload build errors
+        # We don't want to skip this step on failure
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: failures
+          path: failures.tar.gz
 
   sysroots-cron-fail-notify:
     name: sysroots cronjob failure notification
@@ -28,6 +35,11 @@
     needs: [sysroots]
     if: failure() || cancelled()
     steps:
+      # Download our build error logs
+      - name: Download build errors
+        uses: actions/download-artifact@v4
+        with:
+          name: failures
       # Send a Zulip notification
       - name: Install zulip-send
         run: pip3 install zulip
@@ -36,11 +48,12 @@
           ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }}
           ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }}
         run: |
+          tar xf failures.tar.gz
+          ls failures
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
-            --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
-            --message 'Dear @*T-miri*,
-
-          It would appear that the [Miri sysroots cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed.
+            --stream miri --subject "Sysroot Build Errors ($(date -u +%Y-%m))" \
+            --message 'It would appear that the [Miri sysroots cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed to build these targets:
+          '"$(ls failures)"'
 
           Would you mind investigating this issue?
 
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 315f7a2..81ff685 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -95,7 +95,7 @@
     let target = get_arg_flag_value("--target");
     let target = target.as_ref().unwrap_or(host);
 
-    // If cleaning the the target directory & sysroot cache,
+    // If cleaning the target directory & sysroot cache,
     // delete them then exit. There is no reason to setup a new
     // sysroot in this execution.
     if let MiriCommand::Clean = subcommand {
diff --git a/src/tools/miri/ci/build-all-targets.sh b/src/tools/miri/ci/build-all-targets.sh
index fdb645c..b93d4f5 100755
--- a/src/tools/miri/ci/build-all-targets.sh
+++ b/src/tools/miri/ci/build-all-targets.sh
@@ -3,6 +3,7 @@
 set -eu
 set -o pipefail
 
+# .github/workflows/sysroots.yml relies on this name this to report which sysroots didn't build
 FAILS_DIR=failures
 
 rm -rf $FAILS_DIR
@@ -13,14 +14,16 @@
 for target in $(python3 ci/scrape-targets.py $PLATFORM_SUPPORT_FILE); do
     # Wipe the cache before every build to minimize disk usage
     cargo +miri miri clean
-    if cargo +miri miri setup --target $target 2>&1 | tee failures/$target; then
+    if cargo +miri miri setup --target $target 2>&1 | tee $FAILS_DIR/$target; then
         # If the build succeeds, delete its output. If we have output, a build failed.
         rm $FAILS_DIR/$target
     fi
 done
 
+tar czf $FAILS_DIR.tar.gz $FAILS_DIR
+
 # If the sysroot for any target fails to build, we will have a file in FAILS_DIR.
-if [[ $(ls failures | wc -l) -ne 0 ]]; then
+if [[ $(ls $FAILS_DIR | wc -l) -ne 0 ]]; then
     echo "Sysroots for the following targets failed to build:"
     ls $FAILS_DIR
     exit 1
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index e23293e..e32968d 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-4d4bb491b65c300835442f6cb4f34fc9a5685c26
+ee03c286cfdca26fa5b2a4ee40957625d2c826ff
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 4a1c3ac..127d97b 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -1074,7 +1074,12 @@
         size: Size,
         machine: &mut MiriMachine<'_, '_>,
     ) -> InterpResult<'tcx> {
-        self.unique_access(alloc_id, alloc_range(Size::ZERO, size), NaWriteType::Deallocate, machine)
+        self.unique_access(
+            alloc_id,
+            alloc_range(Size::ZERO, size),
+            NaWriteType::Deallocate,
+            machine,
+        )
     }
 }
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 4683965..03428b0 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -527,8 +527,7 @@
     pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
         use NonHaltingDiagnostic::*;
 
-        let stacktrace =
-            MiriInterpCx::generate_stacktrace_from_stack(self.threads.active_thread_stack());
+        let stacktrace = Frame::generate_stacktrace_from_stack(self.threads.active_thread_stack());
         let (stacktrace, _was_pruned) = prune_stacktrace(stacktrace, self);
 
         let (title, diag_level) = match &e {
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 76f4b77..c12fe0e 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -413,7 +413,7 @@
                 .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?;
             // Make the local live, and insert the initial value.
             this.storage_live(local)?;
-            let callee_arg = this.local_to_place(this.frame_idx(), local)?;
+            let callee_arg = this.local_to_place(local)?;
             this.write_immediate(*arg, &callee_arg)?;
         }
         if callee_args.next().is_some() {
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 4dbb814..7e55183 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1488,14 +1488,13 @@
 
     fn after_local_allocated(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        frame: usize,
         local: mir::Local,
         mplace: &MPlaceTy<'tcx, Provenance>,
     ) -> InterpResult<'tcx> {
         let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else {
             panic!("after_local_allocated should only be called on fresh allocations");
         };
-        let local_decl = &ecx.active_thread_stack()[frame].body.local_decls[local];
+        let local_decl = &ecx.frame().body.local_decls[local];
         let span = local_decl.source_info.span;
         ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
         Ok(())
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index bb4c325..9c6994c 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -297,32 +297,6 @@
             }
 
             // Synchronization primitives
-            "AcquireSRWLockExclusive" => {
-                let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                this.AcquireSRWLockExclusive(ptr)?;
-            }
-            "ReleaseSRWLockExclusive" => {
-                let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                this.ReleaseSRWLockExclusive(ptr)?;
-            }
-            "TryAcquireSRWLockExclusive" => {
-                let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                let ret = this.TryAcquireSRWLockExclusive(ptr)?;
-                this.write_scalar(ret, dest)?;
-            }
-            "AcquireSRWLockShared" => {
-                let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                this.AcquireSRWLockShared(ptr)?;
-            }
-            "ReleaseSRWLockShared" => {
-                let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                this.ReleaseSRWLockShared(ptr)?;
-            }
-            "TryAcquireSRWLockShared" => {
-                let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-                let ret = this.TryAcquireSRWLockShared(ptr)?;
-                this.write_scalar(ret, dest)?;
-            }
             "InitOnceBeginInitialize" => {
                 let [ptr, flags, pending, context] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
@@ -335,25 +309,6 @@
                 let result = this.InitOnceComplete(ptr, flags, context)?;
                 this.write_scalar(result, dest)?;
             }
-            "SleepConditionVariableSRW" => {
-                let [condvar, lock, timeout, flags] =
-                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-
-                let result = this.SleepConditionVariableSRW(condvar, lock, timeout, flags, dest)?;
-                this.write_scalar(result, dest)?;
-            }
-            "WakeConditionVariable" => {
-                let [condvar] =
-                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-
-                this.WakeConditionVariable(condvar)?;
-            }
-            "WakeAllConditionVariable" => {
-                let [condvar] =
-                    this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
-
-                this.WakeAllConditionVariable(condvar)?;
-            }
             "WaitOnAddress" => {
                 let [ptr_op, compare_op, size_op, timeout_op] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index 5edc18a..f02939f 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -3,52 +3,14 @@
 use rustc_target::abi::Size;
 
 use crate::concurrency::init_once::InitOnceStatus;
-use crate::concurrency::sync::{CondvarLock, RwLockMode};
 use crate::concurrency::thread::MachineCallback;
 use crate::*;
 
 impl<'mir, 'tcx> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    /// Try to reacquire the lock associated with the condition variable after we
-    /// were signaled.
-    fn reacquire_cond_lock(
-        &mut self,
-        thread: ThreadId,
-        lock: RwLockId,
-        mode: RwLockMode,
-    ) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        this.unblock_thread(thread);
-
-        match mode {
-            RwLockMode::Read =>
-                if this.rwlock_is_write_locked(lock) {
-                    this.rwlock_enqueue_and_block_reader(lock, thread);
-                } else {
-                    this.rwlock_reader_lock(lock, thread);
-                },
-            RwLockMode::Write =>
-                if this.rwlock_is_locked(lock) {
-                    this.rwlock_enqueue_and_block_writer(lock, thread);
-                } else {
-                    this.rwlock_writer_lock(lock, thread);
-                },
-        }
-
-        Ok(())
-    }
-
     // Windows sync primitives are pointer sized.
     // We only use the first 4 bytes for the id.
 
-    fn srwlock_get_id(
-        &mut self,
-        rwlock_op: &OpTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, RwLockId> {
-        let this = self.eval_context_mut();
-        this.rwlock_get_or_create_id(rwlock_op, this.windows_ty_layout("SRWLOCK"), 0)
-    }
-
     fn init_once_get_id(
         &mut self,
         init_once_op: &OpTy<'tcx, Provenance>,
@@ -56,117 +18,11 @@
         let this = self.eval_context_mut();
         this.init_once_get_or_create_id(init_once_op, this.windows_ty_layout("INIT_ONCE"), 0)
     }
-
-    fn condvar_get_id(
-        &mut self,
-        condvar_op: &OpTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, CondvarId> {
-        let this = self.eval_context_mut();
-        this.condvar_get_or_create_id(condvar_op, this.windows_ty_layout("CONDITION_VARIABLE"), 0)
-    }
 }
 
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 #[allow(non_snake_case)]
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let id = this.srwlock_get_id(lock_op)?;
-        let active_thread = this.get_active_thread();
-
-        if this.rwlock_is_locked(id) {
-            // Note: this will deadlock if the lock is already locked by this
-            // thread in any way.
-            //
-            // FIXME: Detect and report the deadlock proactively. (We currently
-            // report the deadlock only when no thread can continue execution,
-            // but we could detect that this lock is already locked and report
-            // an error.)
-            this.rwlock_enqueue_and_block_writer(id, active_thread);
-        } else {
-            this.rwlock_writer_lock(id, active_thread);
-        }
-
-        Ok(())
-    }
-
-    fn TryAcquireSRWLockExclusive(
-        &mut self,
-        lock_op: &OpTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, Scalar<Provenance>> {
-        let this = self.eval_context_mut();
-        let id = this.srwlock_get_id(lock_op)?;
-        let active_thread = this.get_active_thread();
-
-        if this.rwlock_is_locked(id) {
-            // Lock is already held.
-            Ok(Scalar::from_u8(0))
-        } else {
-            this.rwlock_writer_lock(id, active_thread);
-            Ok(Scalar::from_u8(1))
-        }
-    }
-
-    fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let id = this.srwlock_get_id(lock_op)?;
-        let active_thread = this.get_active_thread();
-
-        if !this.rwlock_writer_unlock(id, active_thread) {
-            // The docs do not say anything about this case, but it seems better to not allow it.
-            throw_ub_format!(
-                "calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread"
-            );
-        }
-
-        Ok(())
-    }
-
-    fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let id = this.srwlock_get_id(lock_op)?;
-        let active_thread = this.get_active_thread();
-
-        if this.rwlock_is_write_locked(id) {
-            this.rwlock_enqueue_and_block_reader(id, active_thread);
-        } else {
-            this.rwlock_reader_lock(id, active_thread);
-        }
-
-        Ok(())
-    }
-
-    fn TryAcquireSRWLockShared(
-        &mut self,
-        lock_op: &OpTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, Scalar<Provenance>> {
-        let this = self.eval_context_mut();
-        let id = this.srwlock_get_id(lock_op)?;
-        let active_thread = this.get_active_thread();
-
-        if this.rwlock_is_write_locked(id) {
-            Ok(Scalar::from_u8(0))
-        } else {
-            this.rwlock_reader_lock(id, active_thread);
-            Ok(Scalar::from_u8(1))
-        }
-    }
-
-    fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let id = this.srwlock_get_id(lock_op)?;
-        let active_thread = this.get_active_thread();
-
-        if !this.rwlock_reader_unlock(id, active_thread) {
-            // The docs do not say anything about this case, but it seems better to not allow it.
-            throw_ub_format!(
-                "calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread"
-            );
-        }
-
-        Ok(())
-    }
-
     fn InitOnceBeginInitialize(
         &mut self,
         init_once_op: &OpTy<'tcx, Provenance>,
@@ -399,131 +255,4 @@
 
         Ok(())
     }
-
-    fn SleepConditionVariableSRW(
-        &mut self,
-        condvar_op: &OpTy<'tcx, Provenance>,
-        lock_op: &OpTy<'tcx, Provenance>,
-        timeout_op: &OpTy<'tcx, Provenance>,
-        flags_op: &OpTy<'tcx, Provenance>,
-        dest: &MPlaceTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx, Scalar<Provenance>> {
-        let this = self.eval_context_mut();
-
-        let condvar_id = this.condvar_get_id(condvar_op)?;
-        let lock_id = this.srwlock_get_id(lock_op)?;
-        let timeout_ms = this.read_scalar(timeout_op)?.to_u32()?;
-        let flags = this.read_scalar(flags_op)?.to_u32()?;
-
-        let timeout_time = if timeout_ms == this.eval_windows_u32("c", "INFINITE") {
-            None
-        } else {
-            let duration = Duration::from_millis(timeout_ms.into());
-            Some(this.machine.clock.now().checked_add(duration).unwrap())
-        };
-
-        let shared_mode = 0x1; // CONDITION_VARIABLE_LOCKMODE_SHARED is not in std
-        let mode = if flags == 0 {
-            RwLockMode::Write
-        } else if flags == shared_mode {
-            RwLockMode::Read
-        } else {
-            throw_unsup_format!("unsupported `Flags` {flags} in `SleepConditionVariableSRW`");
-        };
-
-        let active_thread = this.get_active_thread();
-
-        let was_locked = match mode {
-            RwLockMode::Read => this.rwlock_reader_unlock(lock_id, active_thread),
-            RwLockMode::Write => this.rwlock_writer_unlock(lock_id, active_thread),
-        };
-
-        if !was_locked {
-            throw_ub_format!(
-                "calling SleepConditionVariableSRW with an SRWLock that is not locked by the current thread"
-            );
-        }
-
-        this.block_thread(active_thread);
-        this.condvar_wait(condvar_id, active_thread, CondvarLock::RwLock { id: lock_id, mode });
-
-        if let Some(timeout_time) = timeout_time {
-            struct Callback<'tcx> {
-                thread: ThreadId,
-                condvar_id: CondvarId,
-                lock_id: RwLockId,
-                mode: RwLockMode,
-                dest: MPlaceTy<'tcx, Provenance>,
-            }
-
-            impl<'tcx> VisitProvenance for Callback<'tcx> {
-                fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-                    let Callback { thread: _, condvar_id: _, lock_id: _, mode: _, dest } = self;
-                    dest.visit_provenance(visit);
-                }
-            }
-
-            impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
-                fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
-                    this.reacquire_cond_lock(self.thread, self.lock_id, self.mode)?;
-
-                    this.condvar_remove_waiter(self.condvar_id, self.thread);
-
-                    let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT");
-                    this.set_last_error(error_timeout)?;
-                    this.write_scalar(this.eval_windows("c", "FALSE"), &self.dest)?;
-                    Ok(())
-                }
-            }
-
-            this.register_timeout_callback(
-                active_thread,
-                Time::Monotonic(timeout_time),
-                Box::new(Callback {
-                    thread: active_thread,
-                    condvar_id,
-                    lock_id,
-                    mode,
-                    dest: dest.clone(),
-                }),
-            );
-        }
-
-        Ok(this.eval_windows("c", "TRUE"))
-    }
-
-    fn WakeConditionVariable(&mut self, condvar_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let condvar_id = this.condvar_get_id(condvar_op)?;
-
-        if let Some((thread, lock)) = this.condvar_signal(condvar_id) {
-            if let CondvarLock::RwLock { id, mode } = lock {
-                this.reacquire_cond_lock(thread, id, mode)?;
-                this.unregister_timeout_callback_if_exists(thread);
-            } else {
-                panic!("mutexes should not exist on windows");
-            }
-        }
-
-        Ok(())
-    }
-
-    fn WakeAllConditionVariable(
-        &mut self,
-        condvar_op: &OpTy<'tcx, Provenance>,
-    ) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        let condvar_id = this.condvar_get_id(condvar_op)?;
-
-        while let Some((thread, lock)) = this.condvar_signal(condvar_id) {
-            if let CondvarLock::RwLock { id, mode } = lock {
-                this.reacquire_cond_lock(thread, id, mode)?;
-                this.unregister_timeout_callback_if_exists(thread);
-            } else {
-                panic!("mutexes should not exist on windows");
-            }
-        }
-
-        Ok(())
-    }
 }
diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
index 624ad1b..0952b2c 100644
--- a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
+++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs
@@ -1,7 +1,8 @@
+//@compile-flags: -Cpanic=abort
 //@normalize-stderr-test: "OS `.*`" -> "$$OS"
 // Make sure we pretend the allocation symbols don't exist when there is no allocator
 
-#![feature(lang_items, start)]
+#![feature(start)]
 #![no_std]
 
 extern "Rust" {
@@ -21,6 +22,3 @@
 fn panic_handler(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
-
-#[lang = "eh_personality"]
-fn eh_personality() {}
diff --git a/src/tools/miri/tests/fail/panic/no_std.rs b/src/tools/miri/tests/fail/panic/no_std.rs
index 589f843..bad4258 100644
--- a/src/tools/miri/tests/fail/panic/no_std.rs
+++ b/src/tools/miri/tests/fail/panic/no_std.rs
@@ -1,5 +1,6 @@
-#![feature(lang_items, start, core_intrinsics)]
+#![feature(start, core_intrinsics)]
 #![no_std]
+//@compile-flags: -Cpanic=abort
 // windows tls dtors go through libstd right now, thus this test
 // cannot pass. When windows tls dtors go through the special magic
 // windows linker section, we can run this test on windows again.
@@ -36,6 +37,3 @@
     writeln!(HostErr, "{panic_info}").ok();
     core::intrinsics::abort(); //~ ERROR: the program aborted execution
 }
-
-#[lang = "eh_personality"]
-fn eh_personality() {}
diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_condvar_shared.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_condvar_shared.rs
deleted file mode 100644
index 5bff909..0000000
--- a/src/tools/miri/tests/pass-dep/concurrency/windows_condvar_shared.rs
+++ /dev/null
@@ -1,226 +0,0 @@
-//@only-target-windows: Uses win32 api functions
-// We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
-
-use std::ptr::null_mut;
-use std::thread;
-
-use windows_sys::Win32::System::Threading::{
-    AcquireSRWLockExclusive, AcquireSRWLockShared, ReleaseSRWLockExclusive, ReleaseSRWLockShared,
-    SleepConditionVariableSRW, WakeAllConditionVariable, CONDITION_VARIABLE,
-    CONDITION_VARIABLE_LOCKMODE_SHARED, INFINITE, SRWLOCK,
-};
-
-// not in windows-sys
-const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: null_mut() };
-const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: null_mut() };
-
-#[derive(Copy, Clone)]
-struct SendPtr<T>(*mut T);
-
-unsafe impl<T> Send for SendPtr<T> {}
-
-/// threads should be able to reacquire the lock while it is locked by multiple other threads in shared mode
-fn all_shared() {
-    println!("all_shared");
-
-    let mut lock = SRWLOCK_INIT;
-    let mut condvar = CONDITION_VARIABLE_INIT;
-
-    let lock_ptr = SendPtr(&mut lock);
-    let condvar_ptr = SendPtr(&mut condvar);
-
-    let mut handles = Vec::with_capacity(10);
-
-    // waiters
-    for i in 0..5 {
-        handles.push(thread::spawn(move || {
-            let condvar_ptr = condvar_ptr; // avoid field capture
-            let lock_ptr = lock_ptr; // avoid field capture
-            unsafe {
-                AcquireSRWLockShared(lock_ptr.0);
-            }
-            println!("exclusive waiter {i} locked");
-
-            let r = unsafe {
-                SleepConditionVariableSRW(
-                    condvar_ptr.0,
-                    lock_ptr.0,
-                    INFINITE,
-                    CONDITION_VARIABLE_LOCKMODE_SHARED,
-                )
-            };
-            assert_ne!(r, 0);
-
-            println!("exclusive waiter {i} reacquired lock");
-
-            // unlocking is unnecessary because the lock is never used again
-        }));
-    }
-
-    // ensures each waiter is waiting by this point
-    thread::yield_now();
-
-    // readers
-    for i in 0..5 {
-        handles.push(thread::spawn(move || {
-            let lock_ptr = lock_ptr; // avoid field capture
-            unsafe {
-                AcquireSRWLockShared(lock_ptr.0);
-            }
-            println!("reader {i} locked");
-
-            // switch to next reader or main thread
-            thread::yield_now();
-
-            unsafe {
-                ReleaseSRWLockShared(lock_ptr.0);
-            }
-            println!("reader {i} unlocked");
-        }));
-    }
-
-    // ensures each reader has acquired the lock
-    thread::yield_now();
-
-    unsafe {
-        WakeAllConditionVariable(condvar_ptr.0);
-    }
-
-    for handle in handles {
-        handle.join().unwrap();
-    }
-}
-
-// reacquiring a lock should wait until the lock is not exclusively locked
-fn shared_sleep_and_exclusive_lock() {
-    println!("shared_sleep_and_exclusive_lock");
-
-    let mut lock = SRWLOCK_INIT;
-    let mut condvar = CONDITION_VARIABLE_INIT;
-
-    let lock_ptr = SendPtr(&mut lock);
-    let condvar_ptr = SendPtr(&mut condvar);
-
-    let mut waiters = Vec::with_capacity(5);
-    for i in 0..5 {
-        waiters.push(thread::spawn(move || {
-            let lock_ptr = lock_ptr; // avoid field capture
-            let condvar_ptr = condvar_ptr; // avoid field capture
-            unsafe {
-                AcquireSRWLockShared(lock_ptr.0);
-            }
-            println!("shared waiter {i} locked");
-
-            let r = unsafe {
-                SleepConditionVariableSRW(
-                    condvar_ptr.0,
-                    lock_ptr.0,
-                    INFINITE,
-                    CONDITION_VARIABLE_LOCKMODE_SHARED,
-                )
-            };
-            assert_ne!(r, 0);
-
-            println!("shared waiter {i} reacquired lock");
-
-            // unlocking is unnecessary because the lock is never used again
-        }));
-    }
-
-    // ensures each waiter is waiting by this point
-    thread::yield_now();
-
-    unsafe {
-        AcquireSRWLockExclusive(lock_ptr.0);
-    }
-    println!("main locked");
-
-    unsafe {
-        WakeAllConditionVariable(condvar_ptr.0);
-    }
-
-    // waiters are now waiting for the lock to be unlocked
-    thread::yield_now();
-
-    unsafe {
-        ReleaseSRWLockExclusive(lock_ptr.0);
-    }
-    println!("main unlocked");
-
-    for handle in waiters {
-        handle.join().unwrap();
-    }
-}
-
-// threads reacquiring locks should wait for all locks to be released first
-fn exclusive_sleep_and_shared_lock() {
-    println!("exclusive_sleep_and_shared_lock");
-
-    let mut lock = SRWLOCK_INIT;
-    let mut condvar = CONDITION_VARIABLE_INIT;
-
-    let lock_ptr = SendPtr(&mut lock);
-    let condvar_ptr = SendPtr(&mut condvar);
-
-    let mut handles = Vec::with_capacity(10);
-    for i in 0..5 {
-        handles.push(thread::spawn(move || {
-            let lock_ptr = lock_ptr; // avoid field capture
-            let condvar_ptr = condvar_ptr; // avoid field capture
-            unsafe {
-                AcquireSRWLockExclusive(lock_ptr.0);
-            }
-
-            println!("exclusive waiter {i} locked");
-
-            let r = unsafe { SleepConditionVariableSRW(condvar_ptr.0, lock_ptr.0, INFINITE, 0) };
-            assert_ne!(r, 0);
-
-            println!("exclusive waiter {i} reacquired lock");
-
-            // switch to next waiter or main thread
-            thread::yield_now();
-
-            unsafe {
-                ReleaseSRWLockExclusive(lock_ptr.0);
-            }
-            println!("exclusive waiter {i} unlocked");
-        }));
-    }
-
-    for i in 0..5 {
-        handles.push(thread::spawn(move || {
-            let lock_ptr = lock_ptr; // avoid field capture
-            unsafe {
-                AcquireSRWLockShared(lock_ptr.0);
-            }
-            println!("reader {i} locked");
-
-            // switch to next reader or main thread
-            thread::yield_now();
-
-            unsafe {
-                ReleaseSRWLockShared(lock_ptr.0);
-            }
-            println!("reader {i} unlocked");
-        }));
-    }
-
-    // ensures each reader has acquired the lock
-    thread::yield_now();
-
-    unsafe {
-        WakeAllConditionVariable(condvar_ptr.0);
-    }
-
-    for handle in handles {
-        handle.join().unwrap();
-    }
-}
-
-fn main() {
-    all_shared();
-    shared_sleep_and_exclusive_lock();
-    exclusive_sleep_and_shared_lock();
-}
diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_condvar_shared.stdout b/src/tools/miri/tests/pass-dep/concurrency/windows_condvar_shared.stdout
deleted file mode 100644
index 918b546..0000000
--- a/src/tools/miri/tests/pass-dep/concurrency/windows_condvar_shared.stdout
+++ /dev/null
@@ -1,60 +0,0 @@
-all_shared
-exclusive waiter 0 locked
-exclusive waiter 1 locked
-exclusive waiter 2 locked
-exclusive waiter 3 locked
-exclusive waiter 4 locked
-reader 0 locked
-reader 1 locked
-reader 2 locked
-reader 3 locked
-reader 4 locked
-exclusive waiter 0 reacquired lock
-exclusive waiter 1 reacquired lock
-exclusive waiter 2 reacquired lock
-exclusive waiter 3 reacquired lock
-exclusive waiter 4 reacquired lock
-reader 0 unlocked
-reader 1 unlocked
-reader 2 unlocked
-reader 3 unlocked
-reader 4 unlocked
-shared_sleep_and_exclusive_lock
-shared waiter 0 locked
-shared waiter 1 locked
-shared waiter 2 locked
-shared waiter 3 locked
-shared waiter 4 locked
-main locked
-main unlocked
-shared waiter 0 reacquired lock
-shared waiter 1 reacquired lock
-shared waiter 2 reacquired lock
-shared waiter 3 reacquired lock
-shared waiter 4 reacquired lock
-exclusive_sleep_and_shared_lock
-exclusive waiter 0 locked
-exclusive waiter 1 locked
-exclusive waiter 2 locked
-exclusive waiter 3 locked
-exclusive waiter 4 locked
-reader 0 locked
-reader 1 locked
-reader 2 locked
-reader 3 locked
-reader 4 locked
-reader 0 unlocked
-reader 1 unlocked
-reader 2 unlocked
-reader 3 unlocked
-reader 4 unlocked
-exclusive waiter 0 reacquired lock
-exclusive waiter 0 unlocked
-exclusive waiter 1 reacquired lock
-exclusive waiter 1 unlocked
-exclusive waiter 2 reacquired lock
-exclusive waiter 2 unlocked
-exclusive waiter 3 reacquired lock
-exclusive waiter 3 unlocked
-exclusive waiter 4 reacquired lock
-exclusive waiter 4 unlocked
diff --git a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
index ada9cf4..1898093 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
@@ -10,9 +10,9 @@
 use std::{
     alloc::{AllocError, Allocator, Layout},
     cell::{Cell, UnsafeCell},
+    mem,
     ptr::{self, addr_of, NonNull},
     thread::{self, ThreadId},
-    mem,
 };
 
 const BIN_SIZE: usize = 8;
@@ -33,7 +33,7 @@
         }
         // Cast the *entire* thing to a raw pointer to not restrict its provenance.
         let bin = self as *const MyBin;
-        let base_ptr = UnsafeCell::raw_get(unsafe{ addr_of!((*bin).memory )}).cast::<usize>();
+        let base_ptr = UnsafeCell::raw_get(unsafe { addr_of!((*bin).memory) }).cast::<usize>();
         let ptr = unsafe { NonNull::new_unchecked(base_ptr.add(top)) };
         self.top.set(top + 1);
         Some(ptr.cast())
@@ -64,22 +64,14 @@
         MyAllocator {
             thread_id,
             bins: Box::new(
-                [MyBin {
-                    top: Cell::new(0),
-                    thread_id,
-                    memory: UnsafeCell::default(),
-                }; 1],
+                [MyBin { top: Cell::new(0), thread_id, memory: UnsafeCell::default() }; 1],
             ),
         }
     }
 
     // Pretends to be expensive finding a suitable bin for the layout.
     fn find_bin(&self, layout: Layout) -> Option<&MyBin> {
-        if layout == Layout::new::<usize>() {
-            Some(&self.bins[0])
-        } else {
-            None
-        }
+        if layout == Layout::new::<usize>() { Some(&self.bins[0]) } else { None }
     }
 }
 
diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs
index f6464b5..8f17247 100644
--- a/src/tools/miri/tests/pass/miri-alloc.rs
+++ b/src/tools/miri/tests/pass/miri-alloc.rs
@@ -1,5 +1,6 @@
-#![feature(lang_items, start)]
+#![feature(start)]
 #![no_std]
+//@compile-flags: -Cpanic=abort
 // windows tls dtors go through libstd right now, thus this test
 // cannot pass. When windows tls dtors go through the special magic
 // windows linker section, we can run this test on windows again.
@@ -24,6 +25,3 @@
 fn panic_handler(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
-
-#[lang = "eh_personality"]
-fn eh_personality() {}
diff --git a/src/tools/miri/tests/pass/no_std.rs b/src/tools/miri/tests/pass/no_std.rs
index 3bece77..3c98ee5 100644
--- a/src/tools/miri/tests/pass/no_std.rs
+++ b/src/tools/miri/tests/pass/no_std.rs
@@ -1,4 +1,5 @@
-#![feature(lang_items, start)]
+//@compile-flags: -Cpanic=abort
+#![feature(start)]
 #![no_std]
 
 // Plumbing to let us use `writeln!` to host stdout:
@@ -32,6 +33,3 @@
 fn panic_handler(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
-
-#[lang = "eh_personality"]
-fn eh_personality() {}
diff --git a/src/tools/miri/tests/pass/overloaded-calls-simple.rs b/src/tools/miri/tests/pass/overloaded-calls-simple.rs
index 9fcf7d4..d13bf34 100644
--- a/src/tools/miri/tests/pass/overloaded-calls-simple.rs
+++ b/src/tools/miri/tests/pass/overloaded-calls-simple.rs
@@ -1,4 +1,4 @@
-#![feature(lang_items, unboxed_closures, fn_traits)]
+#![feature(unboxed_closures, fn_traits)]
 
 struct S3 {
     x: i32,
diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation.rs b/src/tools/miri/tests/pass/shims/time-with-isolation.rs
index a0c3c6b..645d42a 100644
--- a/src/tools/miri/tests/pass/shims/time-with-isolation.rs
+++ b/src/tools/miri/tests/pass/shims/time-with-isolation.rs
@@ -24,7 +24,8 @@
     assert_eq!(now2 - diff, now1);
     // The virtual clock is deterministic and I got 15ms on a 64-bit Linux machine. However, this
     // changes according to the platform so we use an interval to be safe. This should be updated
-    // if `NANOSECONDS_PER_BASIC_BLOCK` changes.
+    // if `NANOSECONDS_PER_BASIC_BLOCK` changes. It may also need updating if the standard library
+    // code that runs in the loop above changes.
     assert!(diff.as_millis() > 5);
     assert!(diff.as_millis() < 20);
 }
@@ -37,8 +38,18 @@
     while Instant::now() < end {}
 }
 
+/// Ensures that we get the same behavior across all targets.
+fn test_deterministic() {
+    let begin = Instant::now();
+    for _ in 0..100_000 {}
+    let time = begin.elapsed();
+    println!("The loop took around {}s", time.as_secs());
+    println!("(It's fine for this number to change when you `--bless` this test.)")
+}
+
 fn main() {
     test_time_passes();
     test_block_for_one_second();
     test_sleep();
+    test_deterministic();
 }
diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout
new file mode 100644
index 0000000..ff5889b
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/time-with-isolation.stdout
@@ -0,0 +1,2 @@
+The loop took around 12s
+(It's fine for this number to change when you `--bless` this test.)
diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation2.rs b/src/tools/miri/tests/pass/shims/time-with-isolation2.rs
deleted file mode 100644
index 24e72e2..0000000
--- a/src/tools/miri/tests/pass/shims/time-with-isolation2.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-use std::time::Instant;
-
-fn main() {
-    let begin = Instant::now();
-    for _ in 0..100_000 {}
-    let time = begin.elapsed();
-    println!("The loop took around {}s", time.as_secs());
-}
diff --git a/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout b/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout
deleted file mode 100644
index c68b40b..0000000
--- a/src/tools/miri/tests/pass/shims/time-with-isolation2.stdout
+++ /dev/null
@@ -1 +0,0 @@
-The loop took around 7s
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index f694c08..eb10426 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -62,9 +62,11 @@
         // Reorder basic blocks within functions
         .arg("-reorder-blocks=ext-tsp")
         // Reorder functions within the binary
-        .arg("-reorder-functions=hfsort+")
+        .arg("-reorder-functions=cdsort")
         // Split function code into hot and code regions
         .arg("-split-functions")
+        // Split using best available strategy (three-way splitting, Cache-Directed Sort)
+        .arg("-split-strategy=cdsplit")
         // Split as many basic blocks as possible
         .arg("-split-all-cold")
         // Move jump tables to a separate section
diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs
index 4d83547..83f5983 100644
--- a/src/tools/rustfmt/src/attr.rs
+++ b/src/tools/rustfmt/src/attr.rs
@@ -26,7 +26,7 @@
 
 pub(crate) fn get_span_without_attrs(stmt: &ast::Stmt) -> Span {
     match stmt.kind {
-        ast::StmtKind::Local(ref local) => local.span,
+        ast::StmtKind::Let(ref local) => local.span,
         ast::StmtKind::Item(ref item) => item.span,
         ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => expr.span,
         ast::StmtKind::MacCall(ref mac_stmt) => mac_stmt.mac.span(),
diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs
index 5960b14..4aaf7fd 100644
--- a/src/tools/rustfmt/src/spanned.rs
+++ b/src/tools/rustfmt/src/spanned.rs
@@ -61,7 +61,7 @@
 impl Spanned for ast::Stmt {
     fn span(&self) -> Span {
         match self.kind {
-            ast::StmtKind::Local(ref local) => mk_sp(local.span().lo(), self.span.hi()),
+            ast::StmtKind::Let(ref local) => mk_sp(local.span().lo(), self.span.hi()),
             ast::StmtKind::Item(ref item) => mk_sp(item.span().lo(), self.span.hi()),
             ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
                 mk_sp(expr.span().lo(), self.span.hi())
diff --git a/src/tools/rustfmt/src/stmt.rs b/src/tools/rustfmt/src/stmt.rs
index e3fe4eb..73a9cce 100644
--- a/src/tools/rustfmt/src/stmt.rs
+++ b/src/tools/rustfmt/src/stmt.rs
@@ -115,7 +115,7 @@
     skip_out_of_file_lines_range!(context, stmt.span());
 
     let result = match stmt.kind {
-        ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
+        ast::StmtKind::Let(ref local) => local.rewrite(context, shape),
         ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
             let suffix = if semicolon_for_stmt(context, stmt, is_last_expr) {
                 ";"
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 47f772b..6209b37 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -150,7 +150,7 @@
                 self.visit_item(item);
                 self.last_pos = stmt.span().hi();
             }
-            ast::StmtKind::Local(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => {
+            ast::StmtKind::Let(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => {
                 let attrs = get_attrs_from_stmt(stmt.as_ast_node());
                 if contains_skip(attrs) {
                     self.push_skipped_with_span(
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 91bbf50..0ef962c 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1107,7 +1107,6 @@
 "ui/generic-associated-types/issue-92954.rs",
 "ui/generic-associated-types/issue-93141.rs",
 "ui/generic-associated-types/issue-93262.rs",
-"ui/generic-associated-types/issue-93340.rs",
 "ui/generic-associated-types/issue-93341.rs",
 "ui/generic-associated-types/issue-93342.rs",
 "ui/generic-associated-types/issue-93874.rs",
diff --git a/tests/codegen/align-byval-alignment-mismatch.rs b/tests/codegen/align-byval-alignment-mismatch.rs
new file mode 100644
index 0000000..306e3ce
--- /dev/null
+++ b/tests/codegen/align-byval-alignment-mismatch.rs
@@ -0,0 +1,126 @@
+// ignore-tidy-linelength
+//@ revisions:i686-linux x86_64-linux
+
+//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu
+//@[i686-linux] needs-llvm-components: x86
+//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[x86_64-linux] needs-llvm-components: x86
+
+// Tests that we correctly copy arguments into allocas when the alignment of the byval argument
+// is different from the alignment of the Rust type.
+
+// For the following test cases:
+// All of the `*_decreases_alignment` functions should codegen to a direct call, since the
+// alignment is already sufficient.
+// All off the `*_increases_alignment` functions should copy the argument to an alloca
+// on i686-unknown-linux-gnu, since the alignment needs to be increased, and should codegen
+// to a direct call on x86_64-unknown-linux-gnu, where byval alignment matches Rust alignment.
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "freeze"]
+trait Freeze {}
+#[lang = "copy"]
+trait Copy {}
+
+// This type has align 1 in Rust, but as a byval argument on i686-linux, it will have align 4.
+#[repr(C)]
+#[repr(packed)]
+struct Align1 {
+    x: u128,
+    y: u128,
+    z: u128,
+}
+
+// This type has align 16 in Rust, but as a byval argument on i686-linux, it will have align 4.
+#[repr(C)]
+#[repr(align(16))]
+struct Align16 {
+    x: u128,
+    y: u128,
+    z: u128,
+}
+
+extern "C" {
+    fn extern_c_align1(x: Align1);
+    fn extern_c_align16(x: Align16);
+}
+
+// CHECK-LABEL: @rust_to_c_increases_alignment
+#[no_mangle]
+pub unsafe fn rust_to_c_increases_alignment(x: Align1) {
+    // i686-linux: start:
+    // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca %Align1, align 4
+    // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 4 {{.*}}[[ALLOCA]], ptr {{.*}}align 1 {{.*}}%x
+    // i686-linux-NEXT: call void @extern_c_align1({{.+}} [[ALLOCA]])
+
+    // x86_64-linux: start:
+    // x86_64-linux-NEXT: call void @extern_c_align1
+    extern_c_align1(x);
+}
+
+// CHECK-LABEL: @rust_to_c_decreases_alignment
+#[no_mangle]
+pub unsafe fn rust_to_c_decreases_alignment(x: Align16) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @extern_c_align16
+    extern_c_align16(x);
+}
+
+extern "Rust" {
+    fn extern_rust_align1(x: Align1);
+    fn extern_rust_align16(x: Align16);
+}
+
+// CHECK-LABEL: @c_to_rust_decreases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_decreases_alignment(x: Align1) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @extern_rust_align1
+    extern_rust_align1(x);
+}
+
+// CHECK-LABEL: @c_to_rust_increases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_increases_alignment(x: Align16) {
+    // i686-linux: start:
+    // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca %Align16, align 16
+    // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0
+    // i686-linux-NEXT: call void @extern_rust_align16({{.+}} [[ALLOCA]])
+
+    // x86_64-linux: start:
+    // x86_64-linux-NEXT: call void @extern_rust_align16
+    extern_rust_align16(x);
+}
+
+extern "Rust" {
+    fn extern_rust_ref_align1(x: &Align1);
+    fn extern_rust_ref_align16(x: &Align16);
+}
+
+// CHECK-LABEL: @c_to_rust_ref_decreases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_ref_decreases_alignment(x: Align1) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @extern_rust_ref_align1
+    extern_rust_ref_align1(&x);
+}
+
+// CHECK-LABEL: @c_to_rust_ref_increases_alignment
+#[no_mangle]
+pub unsafe extern "C" fn c_to_rust_ref_increases_alignment(x: Align16) {
+    // i686-linux: start:
+    // i686-linux-NEXT: [[ALLOCA:%[0-9a-z]+]] = alloca %Align16, align 16
+    // i686-linux-NEXT: call void @llvm.memcpy.{{.+}}(ptr {{.*}}align 16 {{.*}}[[ALLOCA]], ptr {{.*}}align 4 {{.*}}%0
+    // i686-linux-NEXT: call void @extern_rust_ref_align16({{.+}} [[ALLOCA]])
+
+    // x86_64-linux: start:
+    // x86_64-linux-NEXT: call void @extern_rust_ref_align16
+    extern_rust_ref_align16(&x);
+}
diff --git a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs
new file mode 100644
index 0000000..eeeaebe
--- /dev/null
+++ b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs
@@ -0,0 +1,10 @@
+//! This test checks that we do not monomorphize functions that are only
+//! used to evaluate static items, but never used in runtime code.
+
+//@compile-flags: --crate-type=lib -Copt-level=0
+
+const fn foo() {}
+
+pub static FOO: () = foo();
+
+// CHECK-NOT: define{{.*}}foo{{.*}}
diff --git a/tests/coverage/branch_generics.cov-map b/tests/coverage/branch_generics.cov-map
new file mode 100644
index 0000000..719e97e
--- /dev/null
+++ b/tests/coverage/branch_generics.cov-map
@@ -0,0 +1,54 @@
+Function name: branch_generics::print_size::<()>
+Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 5
+- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
+    = (c1 + (c0 - c1))
+
+Function name: branch_generics::print_size::<u32>
+Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 5
+- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
+    = (c1 + (c0 - c1))
+
+Function name: branch_generics::print_size::<u64>
+Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 5
+- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
+    = (c1 + (c0 - c1))
+
diff --git a/tests/coverage/branch_generics.coverage b/tests/coverage/branch_generics.coverage
new file mode 100644
index 0000000..e7cec15
--- /dev/null
+++ b/tests/coverage/branch_generics.coverage
@@ -0,0 +1,62 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ compile-flags: -Zcoverage-options=branch
+   LL|       |//@ llvm-cov-flags: --show-branches=count
+   LL|       |
+   LL|      3|fn print_size<T>() {
+   LL|      3|    if std::mem::size_of::<T>() > 4 {
+  ------------------
+  |  Branch (LL:8): [True: 0, False: 1]
+  |  Branch (LL:8): [True: 0, False: 1]
+  |  Branch (LL:8): [True: 1, False: 0]
+  ------------------
+   LL|      1|        println!("size > 4");
+   LL|      2|    } else {
+   LL|      2|        println!("size <= 4");
+   LL|      2|    }
+   LL|      3|}
+  ------------------
+  | branch_generics::print_size::<()>:
+  |   LL|      1|fn print_size<T>() {
+  |   LL|      1|    if std::mem::size_of::<T>() > 4 {
+  |  ------------------
+  |  |  Branch (LL:8): [True: 0, False: 1]
+  |  ------------------
+  |   LL|      0|        println!("size > 4");
+  |   LL|      1|    } else {
+  |   LL|      1|        println!("size <= 4");
+  |   LL|      1|    }
+  |   LL|      1|}
+  ------------------
+  | branch_generics::print_size::<u32>:
+  |   LL|      1|fn print_size<T>() {
+  |   LL|      1|    if std::mem::size_of::<T>() > 4 {
+  |  ------------------
+  |  |  Branch (LL:8): [True: 0, False: 1]
+  |  ------------------
+  |   LL|      0|        println!("size > 4");
+  |   LL|      1|    } else {
+  |   LL|      1|        println!("size <= 4");
+  |   LL|      1|    }
+  |   LL|      1|}
+  ------------------
+  | branch_generics::print_size::<u64>:
+  |   LL|      1|fn print_size<T>() {
+  |   LL|      1|    if std::mem::size_of::<T>() > 4 {
+  |  ------------------
+  |  |  Branch (LL:8): [True: 1, False: 0]
+  |  ------------------
+  |   LL|      1|        println!("size > 4");
+  |   LL|      1|    } else {
+  |   LL|      0|        println!("size <= 4");
+  |   LL|      0|    }
+  |   LL|      1|}
+  ------------------
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    print_size::<()>();
+   LL|       |    print_size::<u32>();
+   LL|       |    print_size::<u64>();
+   LL|       |}
+
diff --git a/tests/coverage/branch_generics.rs b/tests/coverage/branch_generics.rs
new file mode 100644
index 0000000..d870ace
--- /dev/null
+++ b/tests/coverage/branch_generics.rs
@@ -0,0 +1,19 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ compile-flags: -Zcoverage-options=branch
+//@ llvm-cov-flags: --show-branches=count
+
+fn print_size<T>() {
+    if std::mem::size_of::<T>() > 4 {
+        println!("size > 4");
+    } else {
+        println!("size <= 4");
+    }
+}
+
+#[coverage(off)]
+fn main() {
+    print_size::<()>();
+    print_size::<u32>();
+    print_size::<u64>();
+}
diff --git a/tests/coverage/branch_guard.cov-map b/tests/coverage/branch_guard.cov-map
new file mode 100644
index 0000000..0b3622f
--- /dev/null
+++ b/tests/coverage/branch_guard.cov-map
@@ -0,0 +1,32 @@
+Function name: branch_guard::branch_match_guard
+Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 6
+- expression 0 operands: lhs = Counter(6), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
+- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 13
+- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
+- Code(Counter(7)) at (prev + 3, 11) to (start + 0, 12)
+- Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10)
+- Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15)
+- Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25)
+- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30)
+    true  = c3
+    false = (c6 - c3)
+- Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10)
+- Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15)
+- Code(Counter(7)) at (prev + 0, 20) to (start + 0, 25)
+- Branch { true: Counter(4), false: Counter(2) } at (prev + 0, 20) to (start + 0, 30)
+    true  = c4
+    false = c2
+- Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10)
+- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10)
+    = (c1 + c2)
+- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2)
+    = ((((c1 + c2) + c3) + c4) + c5)
+
diff --git a/tests/coverage/branch_guard.coverage b/tests/coverage/branch_guard.coverage
new file mode 100644
index 0000000..f89b965
--- /dev/null
+++ b/tests/coverage/branch_guard.coverage
@@ -0,0 +1,45 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ compile-flags: -Zcoverage-options=branch
+   LL|       |//@ llvm-cov-flags: --show-branches=count
+   LL|       |
+   LL|       |macro_rules! no_merge {
+   LL|       |    () => {
+   LL|       |        for _ in 0..1 {}
+   LL|       |    };
+   LL|       |}
+   LL|       |
+   LL|      4|fn branch_match_guard(x: Option<u32>) {
+   LL|      4|    no_merge!();
+   LL|       |
+   LL|      1|    match x {
+   LL|      1|        Some(0) => {
+   LL|      1|            println!("zero");
+   LL|      1|        }
+   LL|      3|        Some(x) if x % 2 == 0 => {
+                           ^2
+  ------------------
+  |  Branch (LL:20): [True: 2, False: 1]
+  ------------------
+   LL|      2|            println!("is nonzero and even");
+   LL|      2|        }
+   LL|      1|        Some(x) if x % 3 == 0 => {
+  ------------------
+  |  Branch (LL:20): [True: 1, False: 0]
+  ------------------
+   LL|      1|            println!("is nonzero and odd, but divisible by 3");
+   LL|      1|        }
+   LL|      0|        _ => {
+   LL|      0|            println!("something else");
+   LL|      0|        }
+   LL|       |    }
+   LL|      4|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    branch_match_guard(Some(0));
+   LL|       |    branch_match_guard(Some(2));
+   LL|       |    branch_match_guard(Some(6));
+   LL|       |    branch_match_guard(Some(3));
+   LL|       |}
+
diff --git a/tests/coverage/branch_guard.rs b/tests/coverage/branch_guard.rs
new file mode 100644
index 0000000..fa049e6
--- /dev/null
+++ b/tests/coverage/branch_guard.rs
@@ -0,0 +1,37 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ compile-flags: -Zcoverage-options=branch
+//@ llvm-cov-flags: --show-branches=count
+
+macro_rules! no_merge {
+    () => {
+        for _ in 0..1 {}
+    };
+}
+
+fn branch_match_guard(x: Option<u32>) {
+    no_merge!();
+
+    match x {
+        Some(0) => {
+            println!("zero");
+        }
+        Some(x) if x % 2 == 0 => {
+            println!("is nonzero and even");
+        }
+        Some(x) if x % 3 == 0 => {
+            println!("is nonzero and odd, but divisible by 3");
+        }
+        _ => {
+            println!("something else");
+        }
+    }
+}
+
+#[coverage(off)]
+fn main() {
+    branch_match_guard(Some(0));
+    branch_match_guard(Some(2));
+    branch_match_guard(Some(6));
+    branch_match_guard(Some(3));
+}
diff --git a/tests/coverage/branch_if.cov-map b/tests/coverage/branch_if.cov-map
new file mode 100644
index 0000000..0dbfd92
--- /dev/null
+++ b/tests/coverage/branch_if.cov-map
@@ -0,0 +1,188 @@
+Function name: branch_if::branch_and
+Raw bytes (56): 0x[01, 01, 04, 05, 09, 0d, 02, 11, 0f, 0d, 02, 08, 01, 2b, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 00, 0d, 00, 0e, 20, 11, 0d, 00, 0d, 00, 0e, 11, 00, 0f, 02, 06, 0f, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(3), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Counter(4), rhs = Expression(3, Add)
+- expression 3 operands: lhs = Counter(3), rhs = Expression(0, Sub)
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 43, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9)
+    true  = c2
+    false = (c1 - c2)
+- Code(Counter(2)) at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(4), false: Counter(3) } at (prev + 0, 13) to (start + 0, 14)
+    true  = c4
+    false = c3
+- Code(Counter(4)) at (prev + 0, 15) to (start + 2, 6)
+- Code(Expression(3, Add)) at (prev + 2, 12) to (start + 2, 6)
+    = (c3 + (c1 - c2))
+- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
+    = (c4 + (c3 + (c1 - c2)))
+
+Function name: branch_if::branch_not
+Raw bytes (224): 0x[01, 01, 29, 05, 09, 09, 02, a3, 01, 0d, 09, 02, a3, 01, 0d, 09, 02, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 15, 8e, 01, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, a3, 01, 01, 08, 00, 0a, 20, 9e, 01, 0d, 00, 08, 00, 0a, 9e, 01, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 9b, 01, 01, 08, 00, 0b, 20, 11, 96, 01, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 96, 01, 02, 06, 00, 07, 93, 01, 01, 08, 00, 0c, 20, 8e, 01, 15, 00, 08, 00, 0c, 8e, 01, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 8b, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 41
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 4 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 6 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 7 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 9 operands: lhs = Expression(38, Add), rhs = Counter(4)
+- expression 10 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 11 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 13 operands: lhs = Expression(38, Add), rhs = Counter(4)
+- expression 14 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 15 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 17 operands: lhs = Counter(4), rhs = Expression(37, Sub)
+- expression 18 operands: lhs = Expression(38, Add), rhs = Counter(4)
+- expression 19 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 20 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 22 operands: lhs = Expression(36, Add), rhs = Counter(5)
+- expression 23 operands: lhs = Counter(4), rhs = Expression(37, Sub)
+- expression 24 operands: lhs = Expression(38, Add), rhs = Counter(4)
+- expression 25 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 26 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 27 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(5)
+- expression 29 operands: lhs = Counter(4), rhs = Expression(37, Sub)
+- expression 30 operands: lhs = Expression(38, Add), rhs = Counter(4)
+- expression 31 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 33 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 34 operands: lhs = Counter(5), rhs = Expression(35, Sub)
+- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(5)
+- expression 36 operands: lhs = Counter(4), rhs = Expression(37, Sub)
+- expression 37 operands: lhs = Expression(38, Add), rhs = Counter(4)
+- expression 38 operands: lhs = Counter(3), rhs = Expression(39, Sub)
+- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(3)
+- expression 40 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+Number of file 0 mappings: 18
+- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9)
+    true  = c2
+    false = (c1 - c2)
+- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17)
+- Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7)
+    = (c1 - c2)
+- Code(Expression(40, Add)) at (prev + 1, 8) to (start + 0, 10)
+    = (c2 + (c1 - c2))
+- Branch { true: Expression(39, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10)
+    true  = ((c2 + (c1 - c2)) - c3)
+    false = c3
+- Code(Expression(39, Sub)) at (prev + 0, 11) to (start + 2, 6)
+    = ((c2 + (c1 - c2)) - c3)
+- Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(38, Add)) at (prev + 1, 8) to (start + 0, 11)
+    = (c3 + ((c2 + (c1 - c2)) - c3))
+- Branch { true: Counter(4), false: Expression(37, Sub) } at (prev + 0, 8) to (start + 0, 11)
+    true  = c4
+    false = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6)
+- Code(Expression(37, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Expression(36, Add)) at (prev + 1, 8) to (start + 0, 12)
+    = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4))
+- Branch { true: Expression(35, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12)
+    true  = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)
+    false = c5
+- Code(Expression(35, Sub)) at (prev + 0, 13) to (start + 2, 6)
+    = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)
+- Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(34, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c5 + ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5))
+
+Function name: branch_if::branch_not_as
+Raw bytes (124): 0x[01, 01, 16, 05, 09, 09, 02, 57, 0d, 09, 02, 57, 0d, 09, 02, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 11, 4a, 4f, 11, 0d, 52, 57, 0d, 09, 02, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 57, 01, 08, 00, 15, 20, 0d, 52, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 52, 02, 06, 00, 07, 4f, 01, 08, 00, 16, 20, 4a, 11, 00, 08, 00, 16, 4a, 00, 17, 02, 06, 11, 02, 06, 00, 07, 47, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 22
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Expression(21, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 4 operands: lhs = Expression(21, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 6 operands: lhs = Counter(3), rhs = Expression(20, Sub)
+- expression 7 operands: lhs = Expression(21, Add), rhs = Counter(3)
+- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 9 operands: lhs = Expression(19, Add), rhs = Counter(4)
+- expression 10 operands: lhs = Counter(3), rhs = Expression(20, Sub)
+- expression 11 operands: lhs = Expression(21, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 13 operands: lhs = Expression(19, Add), rhs = Counter(4)
+- expression 14 operands: lhs = Counter(3), rhs = Expression(20, Sub)
+- expression 15 operands: lhs = Expression(21, Add), rhs = Counter(3)
+- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 17 operands: lhs = Counter(4), rhs = Expression(18, Sub)
+- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(4)
+- expression 19 operands: lhs = Counter(3), rhs = Expression(20, Sub)
+- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(3)
+- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+Number of file 0 mappings: 14
+- Code(Counter(0)) at (prev + 29, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 20)
+- Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 0, 8) to (start + 0, 20)
+    true  = (c1 - c2)
+    false = c2
+- Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6)
+    = (c1 - c2)
+- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(21, Add)) at (prev + 1, 8) to (start + 0, 21)
+    = (c2 + (c1 - c2))
+- Branch { true: Counter(3), false: Expression(20, Sub) } at (prev + 0, 8) to (start + 0, 21)
+    true  = c3
+    false = ((c2 + (c1 - c2)) - c3)
+- Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6)
+- Code(Expression(20, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = ((c2 + (c1 - c2)) - c3)
+- Code(Expression(19, Add)) at (prev + 1, 8) to (start + 0, 22)
+    = (c3 + ((c2 + (c1 - c2)) - c3))
+- Branch { true: Expression(18, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22)
+    true  = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+    false = c4
+- Code(Expression(18, Sub)) at (prev + 0, 23) to (start + 2, 6)
+    = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(17, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4))
+
+Function name: branch_if::branch_or
+Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 53, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9)
+    true  = c2
+    false = (c1 - c2)
+- Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14)
+    = (c1 - c2)
+- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 13) to (start + 0, 14)
+    true  = c3
+    false = c4
+- Code(Expression(3, Add)) at (prev + 0, 15) to (start + 2, 6)
+    = (c2 + c3)
+- Code(Counter(4)) at (prev + 2, 12) to (start + 2, 6)
+- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
+    = ((c2 + c3) + c4)
+
diff --git a/tests/coverage/branch_if.coverage b/tests/coverage/branch_if.coverage
new file mode 100644
index 0000000..2a9a408
--- /dev/null
+++ b/tests/coverage/branch_if.coverage
@@ -0,0 +1,115 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ compile-flags: -Zcoverage-options=branch
+   LL|       |//@ llvm-cov-flags: --show-branches=count
+   LL|       |
+   LL|       |macro_rules! no_merge {
+   LL|       |    () => {
+   LL|       |        for _ in 0..1 {}
+   LL|       |    };
+   LL|       |}
+   LL|       |
+   LL|      3|fn branch_not(a: bool) {
+   LL|      3|    no_merge!();
+   LL|       |
+   LL|      3|    if a {
+  ------------------
+  |  Branch (LL:8): [True: 2, False: 1]
+  ------------------
+   LL|      2|        say("a")
+   LL|      1|    }
+   LL|      3|    if !a {
+  ------------------
+  |  Branch (LL:8): [True: 1, False: 2]
+  ------------------
+   LL|      1|        say("not a");
+   LL|      2|    }
+   LL|      3|    if !!a {
+  ------------------
+  |  Branch (LL:8): [True: 2, False: 1]
+  ------------------
+   LL|      2|        say("not not a");
+   LL|      2|    }
+                   ^1
+   LL|      3|    if !!!a {
+  ------------------
+  |  Branch (LL:8): [True: 1, False: 2]
+  ------------------
+   LL|      1|        say("not not not a");
+   LL|      2|    }
+   LL|      3|}
+   LL|       |
+   LL|      3|fn branch_not_as(a: bool) {
+   LL|      3|    no_merge!();
+   LL|       |
+   LL|      3|    if !(a as bool) {
+  ------------------
+  |  Branch (LL:8): [True: 1, False: 2]
+  ------------------
+   LL|      1|        say("not (a as bool)");
+   LL|      2|    }
+   LL|      3|    if !!(a as bool) {
+  ------------------
+  |  Branch (LL:8): [True: 2, False: 1]
+  ------------------
+   LL|      2|        say("not not (a as bool)");
+   LL|      2|    }
+                   ^1
+   LL|      3|    if !!!(a as bool) {
+  ------------------
+  |  Branch (LL:8): [True: 1, False: 2]
+  ------------------
+   LL|      1|        say("not not (a as bool)");
+   LL|      2|    }
+   LL|      3|}
+   LL|       |
+   LL|     15|fn branch_and(a: bool, b: bool) {
+   LL|     15|    no_merge!();
+   LL|       |
+   LL|     15|    if a && b {
+                          ^12
+  ------------------
+  |  Branch (LL:8): [True: 12, False: 3]
+  |  Branch (LL:13): [True: 8, False: 4]
+  ------------------
+   LL|      8|        say("both");
+   LL|      8|    } else {
+   LL|      7|        say("not both");
+   LL|      7|    }
+   LL|     15|}
+   LL|       |
+   LL|     15|fn branch_or(a: bool, b: bool) {
+   LL|     15|    no_merge!();
+   LL|       |
+   LL|     15|    if a || b {
+                          ^3
+  ------------------
+  |  Branch (LL:8): [True: 12, False: 3]
+  |  Branch (LL:13): [True: 2, False: 1]
+  ------------------
+   LL|     14|        say("either");
+   LL|     14|    } else {
+   LL|      1|        say("neither");
+   LL|      1|    }
+   LL|     15|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn say(message: &str) {
+   LL|       |    core::hint::black_box(message);
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    for a in [false, true, true] {
+   LL|       |        branch_not(a);
+   LL|       |        branch_not_as(a);
+   LL|       |    }
+   LL|       |
+   LL|       |    for a in [false, true, true, true, true] {
+   LL|       |        for b in [false, true, true] {
+   LL|       |            branch_and(a, b);
+   LL|       |            branch_or(a, b);
+   LL|       |        }
+   LL|       |    }
+   LL|       |}
+
diff --git a/tests/coverage/branch_if.rs b/tests/coverage/branch_if.rs
new file mode 100644
index 0000000..151eede
--- /dev/null
+++ b/tests/coverage/branch_if.rs
@@ -0,0 +1,81 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ compile-flags: -Zcoverage-options=branch
+//@ llvm-cov-flags: --show-branches=count
+
+macro_rules! no_merge {
+    () => {
+        for _ in 0..1 {}
+    };
+}
+
+fn branch_not(a: bool) {
+    no_merge!();
+
+    if a {
+        say("a")
+    }
+    if !a {
+        say("not a");
+    }
+    if !!a {
+        say("not not a");
+    }
+    if !!!a {
+        say("not not not a");
+    }
+}
+
+fn branch_not_as(a: bool) {
+    no_merge!();
+
+    if !(a as bool) {
+        say("not (a as bool)");
+    }
+    if !!(a as bool) {
+        say("not not (a as bool)");
+    }
+    if !!!(a as bool) {
+        say("not not (a as bool)");
+    }
+}
+
+fn branch_and(a: bool, b: bool) {
+    no_merge!();
+
+    if a && b {
+        say("both");
+    } else {
+        say("not both");
+    }
+}
+
+fn branch_or(a: bool, b: bool) {
+    no_merge!();
+
+    if a || b {
+        say("either");
+    } else {
+        say("neither");
+    }
+}
+
+#[coverage(off)]
+fn say(message: &str) {
+    core::hint::black_box(message);
+}
+
+#[coverage(off)]
+fn main() {
+    for a in [false, true, true] {
+        branch_not(a);
+        branch_not_as(a);
+    }
+
+    for a in [false, true, true, true, true] {
+        for b in [false, true, true] {
+            branch_and(a, b);
+            branch_or(a, b);
+        }
+    }
+}
diff --git a/tests/coverage/branch_while.cov-map b/tests/coverage/branch_while.cov-map
new file mode 100644
index 0000000..d5f54f1
--- /dev/null
+++ b/tests/coverage/branch_while.cov-map
@@ -0,0 +1,98 @@
+Function name: branch_while::while_cond
+Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 0c, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 10, 20, 09, 0a, 00, 0b, 00, 10, 09, 00, 11, 02, 06, 0a, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18)
+- Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 16)
+    = (c1 + c2)
+- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 16)
+    true  = c2
+    false = ((c1 + c2) - c2)
+- Code(Counter(2)) at (prev + 0, 17) to (start + 2, 6)
+- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2)
+    = ((c1 + c2) - c2)
+
+Function name: branch_while::while_cond_not
+Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 0a, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 0a, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 21, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18)
+- Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 20)
+    = (c1 + c2)
+- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 20)
+    true  = c2
+    false = ((c1 + c2) - c2)
+- Code(Counter(2)) at (prev + 0, 21) to (start + 2, 6)
+- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2)
+    = ((c1 + c2) - c2)
+
+Function name: branch_while::while_op_and
+Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 11, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(4), rhs = Counter(3)
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 18)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 16)
+    = (c1 + c2)
+- Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 11) to (start + 0, 16)
+    true  = ((c1 + c2) - c3)
+    false = c3
+- Code(Expression(2, Sub)) at (prev + 0, 20) to (start + 0, 25)
+    = ((c1 + c2) - c3)
+- Branch { true: Counter(2), false: Counter(4) } at (prev + 0, 20) to (start + 0, 25)
+    true  = c2
+    false = c4
+- Code(Counter(2)) at (prev + 0, 26) to (start + 3, 6)
+- Code(Expression(3, Add)) at (prev + 4, 1) to (start + 0, 2)
+    = (c4 + c3)
+
+Function name: branch_while::while_op_or
+Raw bytes (66): 0x[01, 01, 09, 05, 1b, 09, 0d, 03, 09, 03, 09, 22, 0d, 03, 09, 09, 0d, 22, 0d, 03, 09, 08, 01, 29, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 09, 22, 00, 0b, 00, 10, 22, 00, 14, 00, 19, 20, 0d, 1e, 00, 14, 00, 19, 1b, 00, 1a, 03, 06, 1e, 04, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 9
+- expression 0 operands: lhs = Counter(1), rhs = Expression(6, Add)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 4 operands: lhs = Expression(8, Sub), rhs = Counter(3)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(3)
+- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(2)
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 18)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 16)
+    = (c1 + (c2 + c3))
+- Branch { true: Counter(2), false: Expression(8, Sub) } at (prev + 0, 11) to (start + 0, 16)
+    true  = c2
+    false = ((c1 + (c2 + c3)) - c2)
+- Code(Expression(8, Sub)) at (prev + 0, 20) to (start + 0, 25)
+    = ((c1 + (c2 + c3)) - c2)
+- Branch { true: Counter(3), false: Expression(7, Sub) } at (prev + 0, 20) to (start + 0, 25)
+    true  = c3
+    false = (((c1 + (c2 + c3)) - c2) - c3)
+- Code(Expression(6, Add)) at (prev + 0, 26) to (start + 3, 6)
+    = (c2 + c3)
+- Code(Expression(7, Sub)) at (prev + 4, 1) to (start + 0, 2)
+    = (((c1 + (c2 + c3)) - c2) - c3)
+
diff --git a/tests/coverage/branch_while.coverage b/tests/coverage/branch_while.coverage
new file mode 100644
index 0000000..8d9a6c3
--- /dev/null
+++ b/tests/coverage/branch_while.coverage
@@ -0,0 +1,74 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ compile-flags: -Zcoverage-options=branch
+   LL|       |//@ llvm-cov-flags: --show-branches=count
+   LL|       |
+   LL|       |macro_rules! no_merge {
+   LL|       |    () => {
+   LL|       |        for _ in 0..1 {}
+   LL|       |    };
+   LL|       |}
+   LL|       |
+   LL|      1|fn while_cond() {
+   LL|      1|    no_merge!();
+   LL|       |
+   LL|      1|    let mut a = 8;
+   LL|      9|    while a > 0 {
+  ------------------
+  |  Branch (LL:11): [True: 8, False: 1]
+  ------------------
+   LL|      8|        a -= 1;
+   LL|      8|    }
+   LL|      1|}
+   LL|       |
+   LL|      1|fn while_cond_not() {
+   LL|      1|    no_merge!();
+   LL|       |
+   LL|      1|    let mut a = 8;
+   LL|      9|    while !(a == 0) {
+  ------------------
+  |  Branch (LL:11): [True: 8, False: 1]
+  ------------------
+   LL|      8|        a -= 1;
+   LL|      8|    }
+   LL|      1|}
+   LL|       |
+   LL|      1|fn while_op_and() {
+   LL|      1|    no_merge!();
+   LL|       |
+   LL|      1|    let mut a = 8;
+   LL|      1|    let mut b = 4;
+   LL|      5|    while a > 0 && b > 0 {
+  ------------------
+  |  Branch (LL:11): [True: 5, False: 0]
+  |  Branch (LL:20): [True: 4, False: 1]
+  ------------------
+   LL|      4|        a -= 1;
+   LL|      4|        b -= 1;
+   LL|      4|    }
+   LL|      1|}
+   LL|       |
+   LL|      1|fn while_op_or() {
+   LL|      1|    no_merge!();
+   LL|       |
+   LL|      1|    let mut a = 4;
+   LL|      1|    let mut b = 8;
+   LL|      9|    while a > 0 || b > 0 {
+                                 ^5
+  ------------------
+  |  Branch (LL:11): [True: 4, False: 5]
+  |  Branch (LL:20): [True: 4, False: 1]
+  ------------------
+   LL|      8|        a -= 1;
+   LL|      8|        b -= 1;
+   LL|      8|    }
+   LL|      1|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    while_cond();
+   LL|       |    while_cond_not();
+   LL|       |    while_op_and();
+   LL|       |    while_op_or();
+   LL|       |}
+
diff --git a/tests/coverage/branch_while.rs b/tests/coverage/branch_while.rs
new file mode 100644
index 0000000..507815f
--- /dev/null
+++ b/tests/coverage/branch_while.rs
@@ -0,0 +1,58 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ compile-flags: -Zcoverage-options=branch
+//@ llvm-cov-flags: --show-branches=count
+
+macro_rules! no_merge {
+    () => {
+        for _ in 0..1 {}
+    };
+}
+
+fn while_cond() {
+    no_merge!();
+
+    let mut a = 8;
+    while a > 0 {
+        a -= 1;
+    }
+}
+
+fn while_cond_not() {
+    no_merge!();
+
+    let mut a = 8;
+    while !(a == 0) {
+        a -= 1;
+    }
+}
+
+fn while_op_and() {
+    no_merge!();
+
+    let mut a = 8;
+    let mut b = 4;
+    while a > 0 && b > 0 {
+        a -= 1;
+        b -= 1;
+    }
+}
+
+fn while_op_or() {
+    no_merge!();
+
+    let mut a = 4;
+    let mut b = 8;
+    while a > 0 || b > 0 {
+        a -= 1;
+        b -= 1;
+    }
+}
+
+#[coverage(off)]
+fn main() {
+    while_cond();
+    while_cond_not();
+    while_op_and();
+    while_op_or();
+}
diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout
index 38a3965..12c1b38 100644
--- a/tests/run-make/issue-88756-default-output/output-default.stdout
+++ b/tests/run-make/issue-88756-default-output/output-default.stdout
@@ -147,6 +147,8 @@
                         
         --test-builder PATH
                         The rustc-like binary to use as the test builder
+        --test-builder-wrapper PATH
+                        Wrapper program to pass test-builder and arguments
         --check         Run rustdoc checks
         --generate-redirect-map 
                         Generate JSON file at the top level instead of
diff --git a/tests/run-make/pdb-alt-path/Makefile b/tests/run-make/pdb-alt-path/Makefile
new file mode 100644
index 0000000..7a0ae3b
--- /dev/null
+++ b/tests/run-make/pdb-alt-path/Makefile
@@ -0,0 +1,20 @@
+include ../tools.mk
+
+# only-windows-msvc
+
+all:
+	# Test that we don't have the full path to the PDB file in the binary
+	$(RUSTC) main.rs -g --crate-name my_crate_name --crate-type bin -Cforce-frame-pointers
+	$(CGREP) "my_crate_name.pdb" < $(TMPDIR)/my_crate_name.exe
+	$(CGREP) -v "\\my_crate_name.pdb" < $(TMPDIR)/my_crate_name.exe
+
+	# Test that backtraces still can find debuginfo by checking that they contain symbol names and
+	# source locations.
+	$(TMPDIR)/my_crate_name.exe &> $(TMPDIR)/backtrace.txt
+	$(CGREP) "my_crate_name::fn_in_backtrace" < $(TMPDIR)/backtrace.txt
+	$(CGREP) "main.rs:15" < $(TMPDIR)/backtrace.txt
+
+	# Test that explicitly passed `-Clink-arg=/PDBALTPATH:...` is respected
+	$(RUSTC) main.rs -g --crate-name my_crate_name --crate-type bin -Clink-arg=/PDBALTPATH:abcdefg.pdb -Cforce-frame-pointers
+	$(CGREP) "abcdefg.pdb" < $(TMPDIR)/my_crate_name.exe
+	$(CGREP) -v "my_crate_name.pdb" < $(TMPDIR)/my_crate_name.exe
diff --git a/tests/run-make/pdb-alt-path/main.rs b/tests/run-make/pdb-alt-path/main.rs
new file mode 100644
index 0000000..d38d540
--- /dev/null
+++ b/tests/run-make/pdb-alt-path/main.rs
@@ -0,0 +1,24 @@
+// The various #[inline(never)] annotations and std::hint::black_box calls are
+// an attempt to make unwinding as non-flaky as possible on i686-pc-windows-msvc.
+
+#[inline(never)]
+fn generate_backtrace(x: &u32) {
+    std::hint::black_box(x);
+    let bt = std::backtrace::Backtrace::force_capture();
+    println!("{}", bt);
+    std::hint::black_box(x);
+}
+
+#[inline(never)]
+fn fn_in_backtrace(x: &u32) {
+    std::hint::black_box(x);
+    generate_backtrace(x);
+    std::hint::black_box(x);
+}
+
+fn main() {
+    let x = &41;
+    std::hint::black_box(x);
+    fn_in_backtrace(x);
+    std::hint::black_box(x);
+}
diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js
index 16d1712..ffd1698 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -114,7 +114,7 @@
         original: "(p -> p",
         returned: [],
         userQuery: "(p -> p",
-        error: "Unexpected `-` after `(`",
+        error: "Unclosed `(`",
     },
     {
         query: "::a::b",
@@ -195,7 +195,7 @@
         original: "a (b:",
         returned: [],
         userQuery: "a (b:",
-        error: "Expected `,`, `:` or `->`, found `(`",
+        error: "Unclosed `(`",
     },
     {
         query: "_:",
@@ -330,7 +330,7 @@
         original: 'a<->',
         returned: [],
         userQuery: 'a<->',
-        error: 'Unexpected `-` after `<`',
+        error: 'Unclosed `<`',
     },
     {
         query: "a<a>:",
@@ -357,7 +357,16 @@
         original: "a,:",
         returned: [],
         userQuery: "a,:",
-        error: 'Unexpected `,` in type filter (before `:`)',
+        error: 'Expected type filter before `:`',
+    },
+    {
+        query: "a!:",
+        elems: [],
+        foundElems: 0,
+        original: "a!:",
+        returned: [],
+        userQuery: "a!:",
+        error: 'Unexpected `!` in type filter (before `:`)',
     },
     {
         query: "  a<>  :",
@@ -366,7 +375,7 @@
         original: "a<>  :",
         returned: [],
         userQuery: "a<>  :",
-        error: 'Unexpected `<` in type filter (before `:`)',
+        error: 'Expected `,`, `:` or `->` after `>`, found `:`',
     },
     {
         query: "mod : :",
diff --git a/tests/rustdoc-js-std/parser-hof.js b/tests/rustdoc-js-std/parser-hof.js
new file mode 100644
index 0000000..0b99c45
--- /dev/null
+++ b/tests/rustdoc-js-std/parser-hof.js
@@ -0,0 +1,712 @@
+const PARSED = [
+    // ML-style HOF
+    {
+        query: "(-> F<P>)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "f",
+                        fullPath: ["f"],
+                        pathWithoutLast: [],
+                        pathLast: "f",
+                        generics: [
+                            {
+                                name: "p",
+                                fullPath: ["p"],
+                                pathWithoutLast: [],
+                                pathLast: "p",
+                                generics: [],
+                            },
+                        ],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(-> F<P>)",
+        returned: [],
+        userQuery: "(-> f<p>)",
+        error: null,
+    },
+    {
+        query: "(-> P)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(-> P)",
+        returned: [],
+        userQuery: "(-> p)",
+        error: null,
+    },
+    {
+        query: "(->,a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(->,a)",
+        returned: [],
+        userQuery: "(->,a)",
+        error: null,
+    },
+    {
+        query: "(F<P> ->)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "f",
+                fullPath: ["f"],
+                pathWithoutLast: [],
+                pathLast: "f",
+                generics: [
+                    {
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                    },
+                ],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(F<P> ->)",
+        returned: [],
+        userQuery: "(f<p> ->)",
+        error: null,
+    },
+    {
+        query: "(P ->)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(P ->)",
+        returned: [],
+        userQuery: "(p ->)",
+        error: null,
+    },
+    {
+        query: "(,a->)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(,a->)",
+        returned: [],
+        userQuery: "(,a->)",
+        error: null,
+    },
+    {
+        query: "(aaaaa->a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "aaaaa",
+                fullPath: ["aaaaa"],
+                pathWithoutLast: [],
+                pathLast: "aaaaa",
+                generics: [],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(aaaaa->a)",
+        returned: [],
+        userQuery: "(aaaaa->a)",
+        error: null,
+    },
+    {
+        query: "(aaaaa, b -> a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: -1,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "(aaaaa, b -> a)",
+        error: null,
+    },
+    {
+        query: "primitive:(aaaaa, b -> a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: -1,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: 1,
+        }],
+        foundElems: 1,
+        original: "primitive:(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "primitive:(aaaaa, b -> a)",
+        error: null,
+    },
+    {
+        query: "x, trait:(aaaaa, b -> a)",
+        elems: [
+            {
+                name: "x",
+                fullPath: ["x"],
+                pathWithoutLast: [],
+                pathLast: "x",
+                generics: [],
+                typeFilter: -1,
+            },
+            {
+                name: "->",
+                fullPath: ["->"],
+                pathWithoutLast: [],
+                pathLast: "->",
+                generics: [
+                    {
+                        name: "aaaaa",
+                        fullPath: ["aaaaa"],
+                        pathWithoutLast: [],
+                        pathLast: "aaaaa",
+                        generics: [],
+                        typeFilter: -1,
+                    },
+                    {
+                        name: "b",
+                        fullPath: ["b"],
+                        pathWithoutLast: [],
+                        pathLast: "b",
+                        generics: [],
+                        typeFilter: -1,
+                    },
+                ],
+                bindings: [
+                    [
+                        "output",
+                        [{
+                            name: "a",
+                            fullPath: ["a"],
+                            pathWithoutLast: [],
+                            pathLast: "a",
+                            generics: [],
+                            typeFilter: -1,
+                        }],
+                    ],
+                ],
+                typeFilter: 10,
+            }
+        ],
+        foundElems: 2,
+        original: "x, trait:(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "x, trait:(aaaaa, b -> a)",
+        error: null,
+    },
+    // Rust-style HOF
+    {
+        query: "Fn () -> F<P>",
+        elems: [{
+            name: "fn",
+            fullPath: ["fn"],
+            pathWithoutLast: [],
+            pathLast: "fn",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "f",
+                        fullPath: ["f"],
+                        pathWithoutLast: [],
+                        pathLast: "f",
+                        generics: [
+                            {
+                                name: "p",
+                                fullPath: ["p"],
+                                pathWithoutLast: [],
+                                pathLast: "p",
+                                generics: [],
+                            },
+                        ],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "Fn () -> F<P>",
+        returned: [],
+        userQuery: "fn () -> f<p>",
+        error: null,
+    },
+    {
+        query: "FnMut() -> P",
+        elems: [{
+            name: "fnmut",
+            fullPath: ["fnmut"],
+            pathWithoutLast: [],
+            pathLast: "fnmut",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "FnMut() -> P",
+        returned: [],
+        userQuery: "fnmut() -> p",
+        error: null,
+    },
+    {
+        query: "(FnMut() -> P)",
+        elems: [{
+            name: "fnmut",
+            fullPath: ["fnmut"],
+            pathWithoutLast: [],
+            pathLast: "fnmut",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(FnMut() -> P)",
+        returned: [],
+        userQuery: "(fnmut() -> p)",
+        error: null,
+    },
+    {
+        query: "Fn(F<P>)",
+        elems: [{
+            name: "fn",
+            fullPath: ["fn"],
+            pathWithoutLast: [],
+            pathLast: "fn",
+            generics: [{
+                name: "f",
+                fullPath: ["f"],
+                pathWithoutLast: [],
+                pathLast: "f",
+                generics: [
+                    {
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                    },
+                ],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "Fn(F<P>)",
+        returned: [],
+        userQuery: "fn(f<p>)",
+        error: null,
+    },
+    {
+        query: "primitive:fnonce(aaaaa, b) -> a",
+        elems: [{
+            name: "fnonce",
+            fullPath: ["fnonce"],
+            pathWithoutLast: [],
+            pathLast: "fnonce",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: -1,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: 1,
+        }],
+        foundElems: 1,
+        original: "primitive:fnonce(aaaaa, b) -> a",
+        returned: [],
+        userQuery: "primitive:fnonce(aaaaa, b) -> a",
+        error: null,
+    },
+    {
+        query: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
+        elems: [{
+            name: "fnonce",
+            fullPath: ["fnonce"],
+            pathWithoutLast: [],
+            pathLast: "fnonce",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: 0,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: 10,
+                    }],
+                ],
+            ],
+            typeFilter: 1,
+        }],
+        foundElems: 1,
+        original: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
+        returned: [],
+        userQuery: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
+        error: null,
+    },
+    {
+        query: "x, trait:fn(aaaaa, b -> a)",
+        elems: [
+            {
+                name: "x",
+                fullPath: ["x"],
+                pathWithoutLast: [],
+                pathLast: "x",
+                generics: [],
+                typeFilter: -1,
+            },
+            {
+                name: "fn",
+                fullPath: ["fn"],
+                pathWithoutLast: [],
+                pathLast: "fn",
+                generics: [
+                    {
+                        name: "->",
+                        fullPath: ["->"],
+                        pathWithoutLast: [],
+                        pathLast: "->",
+                        generics: [
+                            {
+                                name: "aaaaa",
+                                fullPath: ["aaaaa"],
+                                pathWithoutLast: [],
+                                pathLast: "aaaaa",
+                                generics: [],
+                                typeFilter: -1,
+                            },
+                            {
+                                name: "b",
+                                fullPath: ["b"],
+                                pathWithoutLast: [],
+                                pathLast: "b",
+                                generics: [],
+                                typeFilter: -1,
+                            },
+                        ],
+                        bindings: [
+                            [
+                                "output",
+                                [{
+                                    name: "a",
+                                    fullPath: ["a"],
+                                    pathWithoutLast: [],
+                                    pathLast: "a",
+                                    generics: [],
+                                    typeFilter: -1,
+                                }],
+                            ],
+                        ],
+                        typeFilter: -1,
+                    },
+                ],
+                bindings: [
+                    [
+                        "output",
+                        [],
+                    ]
+                ],
+                typeFilter: 10,
+            }
+        ],
+        foundElems: 2,
+        original: "x, trait:fn(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "x, trait:fn(aaaaa, b -> a)",
+        error: null,
+    },
+    {
+        query: 'a,b(c)',
+        elems: [
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+                typeFilter: -1,
+            },
+            {
+                name: "b",
+                fullPath: ["b"],
+                pathWithoutLast: [],
+                pathLast: "b",
+                generics: [{
+                    name: "c",
+                    fullPath: ["c"],
+                    pathWithoutLast: [],
+                    pathLast: "c",
+                    generics: [],
+                    typeFilter: -1,
+                }],
+                bindings: [
+                    [
+                        "output",
+                        [],
+                    ]
+                ],
+                typeFilter: -1,
+            }
+        ],
+        foundElems: 2,
+        original: "a,b(c)",
+        returned: [],
+        userQuery: "a,b(c)",
+        error: null,
+    },
+];
diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js
index 26b8c32..499b82a 100644
--- a/tests/rustdoc-js-std/parser-weird-queries.js
+++ b/tests/rustdoc-js-std/parser-weird-queries.js
@@ -38,15 +38,6 @@
         error: null,
     },
     {
-        query: 'a,b(c)',
-        elems: [],
-        foundElems: 0,
-        original: "a,b(c)",
-        returned: [],
-        userQuery: "a,b(c)",
-        error: "Expected `,`, `:` or `->`, found `(`",
-    },
-    {
         query: 'aaa,a',
         elems: [
             {
diff --git a/tests/rustdoc-js/auxiliary/interner.rs b/tests/rustdoc-js/auxiliary/interner.rs
new file mode 100644
index 0000000..c95029b
--- /dev/null
+++ b/tests/rustdoc-js/auxiliary/interner.rs
@@ -0,0 +1,245 @@
+#![feature(associated_type_defaults)]
+
+use std::cmp::Ord;
+use std::fmt::{Debug, Formatter};
+use std::hash::Hash;
+use std::ops::ControlFlow;
+
+pub trait Interner: Sized {
+    type DefId: Copy + Debug + Hash + Ord;
+    type AdtDef: Copy + Debug + Hash + Ord;
+    type GenericArgs: Copy
+        + DebugWithInfcx<Self>
+        + Hash
+        + Ord
+        + IntoIterator<Item = Self::GenericArg>;
+    type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type Term: Copy + Debug + Hash + Ord;
+    type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
+    type BoundVars: IntoIterator<Item = Self::BoundVar>;
+    type BoundVar;
+    type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
+    type Ty: Copy
+        + DebugWithInfcx<Self>
+        + Hash
+        + Ord
+        + Into<Self::GenericArg>
+        + IntoKind<Kind = TyKind<Self>>
+        + TypeSuperVisitable<Self>
+        + Flags
+        + Ty<Self>;
+    type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
+    type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type ParamTy: Copy + Debug + Hash + Ord;
+    type BoundTy: Copy + Debug + Hash + Ord;
+    type PlaceholderTy: Copy + Debug + Hash + Ord + PlaceholderLike;
+    type ErrorGuaranteed: Copy + Debug + Hash + Ord;
+    type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type AllocId: Copy + Debug + Hash + Ord;
+    type Const: Copy
+        + DebugWithInfcx<Self>
+        + Hash
+        + Ord
+        + Into<Self::GenericArg>
+        + IntoKind<Kind = ConstKind<Self>>
+        + ConstTy<Self>
+        + TypeSuperVisitable<Self>
+        + Flags
+        + Const<Self>;
+    type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike;
+    type ParamConst: Copy + Debug + Hash + Ord;
+    type BoundConst: Copy + Debug + Hash + Ord;
+    type ValueConst: Copy + Debug + Hash + Ord;
+    type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type Region: Copy
+        + DebugWithInfcx<Self>
+        + Hash
+        + Ord
+        + Into<Self::GenericArg>
+        + IntoKind<Kind = RegionKind<Self>>
+        + Flags
+        + Region<Self>;
+    type EarlyParamRegion: Copy + Debug + Hash + Ord;
+    type LateParamRegion: Copy + Debug + Hash + Ord;
+    type BoundRegion: Copy + Debug + Hash + Ord;
+    type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Ord;
+    type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike;
+    type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
+    type TraitPredicate: Copy + Debug + Hash + Eq;
+    type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
+    type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
+    type ProjectionPredicate: Copy + Debug + Hash + Eq;
+    type NormalizesTo: Copy + Debug + Hash + Eq;
+    type SubtypePredicate: Copy + Debug + Hash + Eq;
+    type CoercePredicate: Copy + Debug + Hash + Eq;
+    type ClosureKind: Copy + Debug + Hash + Eq;
+
+    // Required method
+    fn mk_canonical_var_infos(
+        self,
+        infos: &[CanonicalVarInfo<Self>]
+    ) -> Self::CanonicalVars;
+}
+
+pub trait DebugWithInfcx<I: Interner>: Debug {
+    // Required method
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut Formatter<'_>
+    ) -> std::fmt::Result;
+}
+
+pub trait TypeVisitable<I: Interner>: Debug + Clone {
+    // Required method
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
+}
+
+pub trait BoundVars<I: Interner> {
+    // Required methods
+    fn bound_vars(&self) -> I::BoundVars;
+    fn has_no_bound_vars(&self) -> bool;
+}
+
+pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
+    // Required method
+    fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
+}
+
+pub struct CanonicalVarInfo<I: Interner> {
+    pub kind: CanonicalVarKind<I>,
+}
+
+pub struct CanonicalVarKind<I>(std::marker::PhantomData<I>);
+
+pub struct TyKind<I>(std::marker::PhantomData<I>);
+
+pub trait IntoKind {
+    type Kind;
+
+    // Required method
+    fn kind(self) -> Self::Kind;
+}
+pub trait Flags {
+    // Required methods
+    fn flags(&self) -> TypeFlags;
+    fn outer_exclusive_binder(&self) -> DebruijnIndex;
+}
+pub struct TypeFlags;
+
+pub trait Ty<I: Interner<Ty = Self>> {
+    // Required method
+    fn new_anon_bound(
+        interner: I,
+        debruijn: DebruijnIndex,
+        var: BoundVar
+    ) -> Self;
+}
+
+pub trait PlaceholderLike {
+    // Required methods
+    fn universe(self) -> UniverseIndex;
+    fn var(self) -> BoundVar;
+    fn with_updated_universe(self, ui: UniverseIndex) -> Self;
+    fn new(ui: UniverseIndex, var: BoundVar) -> Self;
+}
+
+pub struct UniverseIndex;
+
+pub struct BoundVar;
+
+pub struct ConstKind<I>(std::marker::PhantomData<I>);
+pub trait Const<I: Interner<Const = Self>> {
+    // Required method
+    fn new_anon_bound(
+        interner: I,
+        debruijn: DebruijnIndex,
+        var: BoundVar,
+        ty: I::Ty
+    ) -> Self;
+}
+
+pub trait ConstTy<I: Interner> {
+    // Required method
+    fn ty(self) -> I::Ty;
+}
+
+pub struct DebruijnIndex;
+
+pub struct RegionKind<I>(std::marker::PhantomData<I>);
+pub trait Region<I: Interner<Region = Self>> {
+    // Required method
+    fn new_anon_bound(
+        interner: I,
+        debruijn: DebruijnIndex,
+        var: BoundVar
+    ) -> Self;
+}
+
+pub trait TypeVisitor<I: Interner>: Sized {
+    type Result: VisitorResult = ();
+
+    // Provided methods
+    fn visit_binder<T: TypeVisitable<I>>(
+        &mut self,
+        t: &I::Binder<T>
+    ) -> Self::Result { unimplemented!() }
+    fn visit_ty(&mut self, t: I::Ty) -> Self::Result { unimplemented!() }
+    fn visit_region(&mut self, _r: I::Region) -> Self::Result { unimplemented!() }
+    fn visit_const(&mut self, c: I::Const) -> Self::Result { unimplemented!() }
+    fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { unimplemented!() }
+}
+
+pub trait VisitorResult {
+    type Residual;
+
+    // Required methods
+    fn output() -> Self;
+    fn from_residual(residual: Self::Residual) -> Self;
+    fn from_branch(b: ControlFlow<Self::Residual>) -> Self;
+    fn branch(self) -> ControlFlow<Self::Residual>;
+}
+
+impl VisitorResult for () {
+    type Residual = ();
+    fn output() -> Self {}
+    fn from_residual(_: Self::Residual) -> Self {}
+    fn from_branch(_: ControlFlow<Self::Residual>) -> Self {}
+    fn branch(self) -> ControlFlow<Self::Residual> { ControlFlow::Continue(()) }
+}
+
+pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> {
+    pub data: T,
+    pub infcx: &'a Infcx,
+}
+
+pub trait InferCtxtLike {
+    type Interner: Interner;
+
+    // Required methods
+    fn interner(&self) -> Self::Interner;
+    fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
+    fn root_ty_var(&self, vid: TyVid) -> TyVid;
+    fn probe_ty_var(
+        &self,
+        vid: TyVid
+    ) -> Option<<Self::Interner as Interner>::Ty>;
+    fn universe_of_lt(
+        &self,
+        lt: <Self::Interner as Interner>::InferRegion
+    ) -> Option<UniverseIndex>;
+    fn opportunistic_resolve_lt_var(
+        &self,
+        vid: <Self::Interner as Interner>::InferRegion
+    ) -> Option<<Self::Interner as Interner>::Region>;
+    fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
+    fn root_ct_var(&self, vid: ConstVid) -> ConstVid;
+    fn probe_ct_var(
+        &self,
+        vid: ConstVid
+    ) -> Option<<Self::Interner as Interner>::Const>;
+}
+
+pub struct TyVid;
+pub struct ConstVid;
diff --git a/tests/rustdoc-js/hof.js b/tests/rustdoc-js/hof.js
new file mode 100644
index 0000000..5e6c9d8
--- /dev/null
+++ b/tests/rustdoc-js/hof.js
@@ -0,0 +1,176 @@
+// exact-check
+
+const EXPECTED = [
+    // not a HOF query
+    {
+        'query': 'u32 -> !',
+        'others': [],
+    },
+
+    // ML-style higher-order function notation
+    {
+        'query': 'bool, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'u8, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': 'i8, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': 'char, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_"},
+        ],
+    },
+    {
+        'query': '(first<u32> -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': '(second<u32> -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': '(third<u32> -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': '(u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_"},
+            {"path": "hof", "name": "fn_ptr"},
+            {"path": "hof", "name": "fn_mut"},
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': '(str, str -> i8) -> ()',
+        'others': [
+            {"path": "hof", "name": "multiple"},
+        ],
+    },
+    {
+        'query': '(str ->) -> ()',
+        'others': [
+            {"path": "hof", "name": "multiple"},
+        ],
+    },
+    {
+        'query': '(-> i8) -> ()',
+        'others': [
+            {"path": "hof", "name": "multiple"},
+        ],
+    },
+    {
+        'query': '(str -> str) -> ()',
+        // params and return are not the same
+        'others': [],
+    },
+    {
+        'query': '(i8 ->) -> ()',
+        // params and return are not the same
+        'others': [],
+    },
+    {
+        'query': '(-> str) -> ()',
+        // params and return are not the same
+        'others': [],
+    },
+
+    // Rust-style higher-order function notation
+    {
+        'query': 'bool, fn(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'u8, fnonce(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': 'u8, fn(u32) -> ! -> ()',
+        // fnonce != fn
+        'others': [],
+    },
+    {
+        'query': 'i8, fnmut(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': 'i8, fn(u32) -> ! -> ()',
+        // fnmut != fn
+        'others': [],
+    },
+    {
+        'query': 'char, fn(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_"},
+        ],
+    },
+    {
+        'query': 'char, fnmut(u32) -> ! -> ()',
+        // fn != fnmut
+        'others': [],
+    },
+    {
+        'query': 'fn(first<u32>) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'fnonce(second<u32>) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': 'fnmut(third<u32>) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': 'fn(u32) -> ! -> ()',
+        'others': [
+            // fn matches primitive:fn and trait:Fn
+            {"path": "hof", "name": "fn_"},
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'trait:fn(u32) -> ! -> ()',
+        'others': [
+            // fn matches primitive:fn and trait:Fn
+            {"path": "hof", "name": "fn_"},
+        ],
+    },
+    {
+        'query': 'primitive:fn(u32) -> ! -> ()',
+        'others': [
+            // fn matches primitive:fn and trait:Fn
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/hof.rs b/tests/rustdoc-js/hof.rs
new file mode 100644
index 0000000..4d2c6e3
--- /dev/null
+++ b/tests/rustdoc-js/hof.rs
@@ -0,0 +1,12 @@
+#![feature(never_type)]
+
+pub struct First<T>(T);
+pub struct Second<T>(T);
+pub struct Third<T>(T);
+
+pub fn fn_ptr(_: fn (First<u32>) -> !, _: bool) {}
+pub fn fn_once(_: impl FnOnce (Second<u32>) -> !, _: u8) {}
+pub fn fn_mut(_: impl FnMut (Third<u32>) -> !, _: i8) {}
+pub fn fn_(_: impl Fn (u32) -> !, _: char) {}
+
+pub fn multiple(_: impl Fn(&'static str, &'static str) -> i8) {}
diff --git a/tests/rustdoc-js/looks-like-rustc-interner.js b/tests/rustdoc-js/looks-like-rustc-interner.js
new file mode 100644
index 0000000..a4806d2
--- /dev/null
+++ b/tests/rustdoc-js/looks-like-rustc-interner.js
@@ -0,0 +1,9 @@
+// https://github.com/rust-lang/rust/pull/122247
+// exact-check
+
+const EXPECTED = {
+    'query': 'canonicalvarinfo, intoiterator -> intoiterator',
+    'others': [
+        { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' },
+    ],
+};
diff --git a/tests/rustdoc-js/looks-like-rustc-interner.rs b/tests/rustdoc-js/looks-like-rustc-interner.rs
new file mode 100644
index 0000000..f304e28
--- /dev/null
+++ b/tests/rustdoc-js/looks-like-rustc-interner.rs
@@ -0,0 +1,5 @@
+//@ aux-crate:interner=interner.rs
+// https://github.com/rust-lang/rust/pull/122247
+extern crate interner;
+#[doc(inline)]
+pub use interner::*;
diff --git a/tests/rustdoc/display-hidden-items.rs b/tests/rustdoc/display-hidden-items.rs
index 7612455..901ca17 100644
--- a/tests/rustdoc/display-hidden-items.rs
+++ b/tests/rustdoc/display-hidden-items.rs
@@ -5,19 +5,22 @@
 #![crate_name = "foo"]
 
 // @has 'foo/index.html'
-// @has - '//*[@id="reexport.hidden_reexport"]/code' 'pub use hidden::inside_hidden as hidden_reexport;'
+// @has - '//*[@class="item-name"]/span[@title="Hidden item"]' '👻'
+
+// @has - '//*[@id="reexport.hidden_reexport"]/code' '#[doc(hidden)] pub use hidden::inside_hidden as hidden_reexport;'
 #[doc(hidden)]
 pub use hidden::inside_hidden as hidden_reexport;
 
 // @has - '//*[@class="item-name"]/a[@class="trait"]' 'TraitHidden'
 // @has 'foo/trait.TraitHidden.html'
+// @has - '//code' '#[doc(hidden)] pub trait TraitHidden'
 #[doc(hidden)]
 pub trait TraitHidden {}
 
 // @has 'foo/index.html' '//*[@class="item-name"]/a[@class="trait"]' 'Trait'
 pub trait Trait {
     // @has 'foo/trait.Trait.html'
-    // @has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0u32'
+    // @has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32'
     #[doc(hidden)]
     const BAR: u32 = 0;
 
@@ -41,14 +44,15 @@
 }
 
 impl Trait for Struct {
-    // @has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0u32'
-    // @has - '//*[@id="method.foo"]/*[@class="code-header"]' 'fn foo()'
+    // @has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32'
+    // @has - '//*[@id="method.foo"]/*[@class="code-header"]' '#[doc(hidden)] fn foo()'
 }
 // @has - '//*[@id="impl-TraitHidden-for-Struct"]/*[@class="code-header"]' 'impl TraitHidden for Struct'
 impl TraitHidden for Struct {}
 
 // @has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'HiddenEnum'
 // @has 'foo/enum.HiddenEnum.html'
+// @has - '//code' '#[doc(hidden)] pub enum HiddenEnum'
 #[doc(hidden)]
 pub enum HiddenEnum {
     A,
diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs
new file mode 100644
index 0000000..e7d852a
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_transform.rs
@@ -0,0 +1,147 @@
+//@ run-pass
+//! Test a few methods to transform StableMIR.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+#![feature(ascii_char, ascii_char_variants)]
+
+extern crate rustc_hir;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_smir::rustc_internal;
+use stable_mir::mir::alloc::GlobalAlloc;
+use stable_mir::mir::mono::Instance;
+use stable_mir::mir::{Body, Constant, Operand, Rvalue, StatementKind, TerminatorKind};
+use stable_mir::ty::{Const, ConstantKind};
+use stable_mir::{CrateDef, CrateItems, ItemKind};
+use std::convert::TryFrom;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to transform the MIR.
+fn test_transform() -> ControlFlow<()> {
+    // Find items in the local crate.
+    let items = stable_mir::all_local_items();
+
+    // Test fn_abi
+    let target_fn = *get_item(&items, (ItemKind::Fn, "dummy")).unwrap();
+    let instance = Instance::try_from(target_fn).unwrap();
+    let body = instance.body().unwrap();
+    check_msg(&body, "oops");
+
+    let new_msg = "new panic message";
+    let new_body = change_panic_msg(body, new_msg);
+    check_msg(&new_body, new_msg);
+
+    ControlFlow::Continue(())
+}
+
+/// Check that the body panic message matches the given message.
+fn check_msg(body: &Body, expected: &str) {
+    let msg = body
+        .blocks
+        .iter()
+        .find_map(|bb| match &bb.terminator.kind {
+            TerminatorKind::Call { args, .. } => {
+                assert_eq!(args.len(), 1, "Expected panic message, but found {args:?}");
+                let msg_const = match &args[0] {
+                    Operand::Constant(msg_const) => msg_const,
+                    Operand::Copy(place) | Operand::Move(place) => {
+                        assert!(place.projection.is_empty());
+                        bb.statements
+                            .iter()
+                            .find_map(|stmt| match &stmt.kind {
+                                StatementKind::Assign(
+                                    destination,
+                                    Rvalue::Use(Operand::Constant(msg_const)),
+                                ) if destination == place => Some(msg_const),
+                                _ => None,
+                            })
+                            .unwrap()
+                    }
+                };
+                let ConstantKind::Allocated(alloc) = msg_const.literal.kind() else {
+                    unreachable!()
+                };
+                assert_eq!(alloc.provenance.ptrs.len(), 1);
+
+                let alloc_prov_id = alloc.provenance.ptrs[0].1 .0;
+                let GlobalAlloc::Memory(val) = GlobalAlloc::from(alloc_prov_id) else {
+                    unreachable!()
+                };
+                let bytes = val.raw_bytes().unwrap();
+                Some(std::str::from_utf8(&bytes).unwrap().to_string())
+            }
+            _ => None,
+        })
+        .expect("Failed to find panic message");
+    assert_eq!(&msg, expected);
+}
+
+/// Modify body to use a different panic message.
+fn change_panic_msg(mut body: Body, new_msg: &str) -> Body {
+    for bb in &mut body.blocks {
+        match &mut bb.terminator.kind {
+            TerminatorKind::Call { args, .. } => {
+                let new_const = Const::from_str(new_msg);
+                args[0] = Operand::Constant(Constant {
+                    literal: new_const,
+                    span: bb.terminator.span,
+                    user_ty: None,
+                });
+            }
+            _ => {}
+        }
+    }
+    body
+}
+
+fn get_item<'a>(
+    items: &'a CrateItems,
+    item: (ItemKind, &str),
+) -> Option<&'a stable_mir::CrateItem> {
+    items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "transform_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_transform).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        #![feature(panic_internals)]
+        pub fn dummy() {{
+            core::panicking::panic_str("oops");
+        }}
+        "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/associated-type-bounds/dedup-normalized-1.rs b/tests/ui/associated-type-bounds/dedup-normalized-1.rs
new file mode 100644
index 0000000..5329018
--- /dev/null
+++ b/tests/ui/associated-type-bounds/dedup-normalized-1.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+
+// We try to prove `T::Rigid: Into<?0>` and have 2 candidates from where-clauses:
+//
+// - `Into<String>`
+// - `Into<<T::Rigid as Elaborate>::Assoc>`
+//
+// This causes ambiguity unless we normalize the alias in the second candidate
+// to detect that they actually result in the same constraints.
+trait Trait {
+    type Rigid: Elaborate<Assoc = String> + Into<String>;
+}
+
+trait Elaborate: Into<Self::Assoc> {
+    type Assoc;
+}
+
+fn impls<T: Into<U>, U>(_: T) {}
+
+fn test<P: Trait>(rigid: P::Rigid) {
+    impls(rigid);
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs
new file mode 100644
index 0000000..9224d47
--- /dev/null
+++ b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.rs
@@ -0,0 +1,27 @@
+// We try to prove `for<'b> T::Rigid: Bound<'b, ?0>` and have 2 candidates from where-clauses:
+//
+// - `for<'a> Bound<'a, String>`
+// - `for<'a> Bound<'a, <T::Rigid as Elaborate>::Assoc>`
+//
+// This causes ambiguity unless we normalize the alias in the second candidate
+// to detect that they actually result in the same constraints. We currently
+// fail to detect that the constraints from these bounds are equal and error
+// with ambiguity.
+trait Bound<'a, U> {}
+
+trait Trait {
+    type Rigid: Elaborate<Assoc = String> + for<'a> Bound<'a, String>;
+}
+
+trait Elaborate: for<'a> Bound<'a, Self::Assoc> {
+    type Assoc;
+}
+
+fn impls<T: for<'b> Bound<'b, U>, U>(_: T) {}
+
+fn test<P: Trait>(rigid: P::Rigid) {
+    impls(rigid);
+    //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.stderr b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.stderr
new file mode 100644
index 0000000..372d379
--- /dev/null
+++ b/tests/ui/associated-type-bounds/dedup-normalized-2-higher-ranked.stderr
@@ -0,0 +1,20 @@
+error[E0283]: type annotations needed
+  --> $DIR/dedup-normalized-2-higher-ranked.rs:23:5
+   |
+LL |     impls(rigid);
+   |     ^^^^^ cannot infer type of the type parameter `U` declared on the function `impls`
+   |
+   = note: cannot satisfy `for<'b> <P as Trait>::Rigid: Bound<'b, _>`
+note: required by a bound in `impls`
+  --> $DIR/dedup-normalized-2-higher-ranked.rs:20:13
+   |
+LL | fn impls<T: for<'b> Bound<'b, U>, U>(_: T) {}
+   |             ^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls`
+help: consider specifying the generic arguments
+   |
+LL |     impls::<<P as Trait>::Rigid, U>(rigid);
+   |          ++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/async-await/in-trait/hir-hash.rs b/tests/ui/async-await/in-trait/hir-hash.rs
new file mode 100644
index 0000000..8324fec
--- /dev/null
+++ b/tests/ui/async-await/in-trait/hir-hash.rs
@@ -0,0 +1,11 @@
+// Issue #122508
+
+//@ check-pass
+//@ incremental
+//@ edition:2021
+
+trait MyTrait {
+    async fn bar(&self) -> i32;
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
index feae269..23ede08 100644
--- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
@@ -7,7 +7,7 @@
    = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0308]: mismatched types
+error: implementation of `Send` is not general enough
   --> $DIR/issue-110963-early.rs:14:5
    |
 LL | /     spawn(async move {
@@ -16,17 +16,12 @@
 LL | |             log_health_check_failure().await;
 LL | |         }
 LL | |     });
-   | |______^ one type is more general than the other
+   | |______^ implementation of `Send` is not general enough
    |
-   = note: expected trait `Send`
-              found trait `for<'a> Send`
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-110963-early.rs:34:17
-   |
-LL |     F: Future + Send + 'static,
-   |                 ^^^^
+   = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>() }`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>() }`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `Send` is not general enough
   --> $DIR/issue-110963-early.rs:14:5
    |
 LL | /     spawn(async move {
@@ -35,17 +30,11 @@
 LL | |             log_health_check_failure().await;
 LL | |         }
 LL | |     });
-   | |______^ one type is more general than the other
+   | |______^ implementation of `Send` is not general enough
    |
-   = note: expected trait `Send`
-              found trait `for<'a> Send`
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-110963-early.rs:34:17
-   |
-LL |     F: Future + Send + 'static,
-   |                 ^^^^
+   = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>() }`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>() }`, for some specific lifetime `'2`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/borrowck/clone-on-ref.fixed b/tests/ui/borrowck/clone-on-ref.fixed
new file mode 100644
index 0000000..b6927ba
--- /dev/null
+++ b/tests/ui/borrowck/clone-on-ref.fixed
@@ -0,0 +1,32 @@
+//@ run-rustfix
+fn foo<T: Default + Clone>(list: &mut Vec<T>) {
+    let mut cloned_items = Vec::new();
+    for v in list.iter() {
+        cloned_items.push(v.clone())
+    }
+    list.push(T::default());
+    //~^ ERROR cannot borrow `*list` as mutable because it is also borrowed as immutable
+    drop(cloned_items);
+}
+fn bar<T: std::fmt::Display + Clone>(x: T) {
+    let a = &x;
+    let b = a.clone();
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{b}");
+}
+#[derive(Debug)]
+#[derive(Clone)]
+struct A;
+fn qux(x: A) {
+    let a = &x;
+    let b = a.clone();
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{b:?}");
+}
+fn main() {
+    foo(&mut vec![1, 2, 3]);
+    bar("");
+    qux(A);
+}
diff --git a/tests/ui/borrowck/clone-on-ref.rs b/tests/ui/borrowck/clone-on-ref.rs
new file mode 100644
index 0000000..f8c94d3
--- /dev/null
+++ b/tests/ui/borrowck/clone-on-ref.rs
@@ -0,0 +1,31 @@
+//@ run-rustfix
+fn foo<T: Default>(list: &mut Vec<T>) {
+    let mut cloned_items = Vec::new();
+    for v in list.iter() {
+        cloned_items.push(v.clone())
+    }
+    list.push(T::default());
+    //~^ ERROR cannot borrow `*list` as mutable because it is also borrowed as immutable
+    drop(cloned_items);
+}
+fn bar<T: std::fmt::Display>(x: T) {
+    let a = &x;
+    let b = a.clone();
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{b}");
+}
+#[derive(Debug)]
+struct A;
+fn qux(x: A) {
+    let a = &x;
+    let b = a.clone();
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{b:?}");
+}
+fn main() {
+    foo(&mut vec![1, 2, 3]);
+    bar("");
+    qux(A);
+}
diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr
new file mode 100644
index 0000000..ee4fcad
--- /dev/null
+++ b/tests/ui/borrowck/clone-on-ref.stderr
@@ -0,0 +1,64 @@
+error[E0502]: cannot borrow `*list` as mutable because it is also borrowed as immutable
+  --> $DIR/clone-on-ref.rs:7:5
+   |
+LL |     for v in list.iter() {
+   |              ---- immutable borrow occurs here
+LL |         cloned_items.push(v.clone())
+   |                             ------- this call doesn't do anything, the result is still `&T` because `T` doesn't implement `Clone`
+LL |     }
+LL |     list.push(T::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     drop(cloned_items);
+   |          ------------ immutable borrow later used here
+   |
+help: consider further restricting this bound
+   |
+LL | fn foo<T: Default + Clone>(list: &mut Vec<T>) {
+   |                   +++++++
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/clone-on-ref.rs:14:10
+   |
+LL | fn bar<T: std::fmt::Display>(x: T) {
+   |                              - binding `x` declared here
+LL |     let a = &x;
+   |             -- borrow of `x` occurs here
+LL |     let b = a.clone();
+   |               ------- this call doesn't do anything, the result is still `&T` because `T` doesn't implement `Clone`
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{b}");
+   |               --- borrow later used here
+   |
+help: consider further restricting this bound
+   |
+LL | fn bar<T: std::fmt::Display + Clone>(x: T) {
+   |                             +++++++
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/clone-on-ref.rs:23:10
+   |
+LL | fn qux(x: A) {
+   |        - binding `x` declared here
+LL |     let a = &x;
+   |             -- borrow of `x` occurs here
+LL |     let b = a.clone();
+   |               ------- this call doesn't do anything, the result is still `&A` because `A` doesn't implement `Clone`
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{b:?}");
+   |               ----- borrow later used here
+   |
+help: consider annotating `A` with `#[derive(Clone)]`
+   |
+LL + #[derive(Clone)]
+LL | struct A;
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0502, E0505.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/tests/ui/closures/multiple-fn-bounds.stderr b/tests/ui/closures/multiple-fn-bounds.stderr
index 9a49fc9..861b39b 100644
--- a/tests/ui/closures/multiple-fn-bounds.stderr
+++ b/tests/ui/closures/multiple-fn-bounds.stderr
@@ -8,7 +8,7 @@
    |     expected due to this
    |
    = note: expected closure signature `fn(_) -> _`
-              found closure signature `for<'a> fn(&'a _) -> _`
+              found closure signature `fn(&_) -> _`
 note: closure inferred to have a different signature due to this bound
   --> $DIR/multiple-fn-bounds.rs:1:11
    |
diff --git a/tests/ui/consts/assoc_const_generic_impl.stderr b/tests/ui/consts/assoc_const_generic_impl.stderr
index d826972..4521950 100644
--- a/tests/ui/consts/assoc_const_generic_impl.stderr
+++ b/tests/ui/consts/assoc_const_generic_impl.stderr
@@ -4,6 +4,12 @@
 LL |     const I_AM_ZERO_SIZED: ()  = [()][std::mem::size_of::<Self>()];
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4
 
+note: erroneous constant encountered
+  --> $DIR/assoc_const_generic_impl.rs:11:9
+   |
+LL |         Self::I_AM_ZERO_SIZED;
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
 note: the above error was encountered while instantiating `fn <u32 as ZeroSized>::requires_zero_size`
   --> $DIR/assoc_const_generic_impl.rs:18:5
    |
diff --git a/tests/ui/consts/const-eval/erroneous-const.rs b/tests/ui/consts/const-eval/erroneous-const.rs
deleted file mode 100644
index 74d44c5..0000000
--- a/tests/ui/consts/const-eval/erroneous-const.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-//! Make sure we error on erroneous consts even if they are unused.
-#![allow(unconditional_panic)]
-
-struct PrintName<T>(T);
-impl<T> PrintName<T> {
-    const VOID: () = [()][2]; //~ERROR evaluation of `PrintName::<i32>::VOID` failed
-}
-
-const fn no_codegen<T>() {
-    if false {
-        // This bad constant is only used in dead code in a no-codegen function... and yet we still
-        // must make sure that the build fails.
-            PrintName::<T>::VOID; //~ constant
-    }
-}
-
-pub static FOO: () = no_codegen::<i32>();
-
-fn main() {
-    FOO
-}
diff --git a/tests/ui/consts/const-eval/erroneous-const.stderr b/tests/ui/consts/const-eval/erroneous-const.stderr
deleted file mode 100644
index bd25e96..0000000
--- a/tests/ui/consts/const-eval/erroneous-const.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
-  --> $DIR/erroneous-const.rs:6:22
-   |
-LL |     const VOID: () = [()][2];
-   |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
-
-note: erroneous constant encountered
-  --> $DIR/erroneous-const.rs:13:13
-   |
-LL |             PrintName::<T>::VOID;
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/erroneous-const2.rs b/tests/ui/consts/const-eval/erroneous-const2.rs
deleted file mode 100644
index 61f2955..0000000
--- a/tests/ui/consts/const-eval/erroneous-const2.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//! Make sure we error on erroneous consts even if they are unused.
-#![allow(unconditional_panic)]
-
-struct PrintName<T>(T);
-impl<T> PrintName<T> {
-    const VOID: () = [()][2]; //~ERROR evaluation of `PrintName::<i32>::VOID` failed
-}
-
-pub static FOO: () = {
-    if false {
-        // This bad constant is only used in dead code in a static initializer... and yet we still
-        // must make sure that the build fails.
-        PrintName::<i32>::VOID; //~ constant
-    }
-};
-
-fn main() {
-    FOO
-}
diff --git a/tests/ui/consts/const-eval/erroneous-const2.stderr b/tests/ui/consts/const-eval/erroneous-const2.stderr
deleted file mode 100644
index 6a5839e..0000000
--- a/tests/ui/consts/const-eval/erroneous-const2.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
-  --> $DIR/erroneous-const2.rs:6:22
-   |
-LL |     const VOID: () = [()][2];
-   |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
-
-note: erroneous constant encountered
-  --> $DIR/erroneous-const2.rs:13:9
-   |
-LL |         PrintName::<i32>::VOID;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
index 4e7ef52..7facb2d 100644
--- a/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
+++ b/tests/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -4,6 +4,12 @@
 LL |     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
    |                                                             ^^^^^ index out of bounds: the length is 0 but the index is 0
 
+note: erroneous constant encountered
+  --> $DIR/index-out-of-bounds-never-type.rs:16:13
+   |
+LL |     let _ = PrintName::<T>::VOID;
+   |             ^^^^^^^^^^^^^^^^^^^^
+
 note: the above error was encountered while instantiating `fn f::<()>`
   --> $DIR/index-out-of-bounds-never-type.rs:20:5
    |
diff --git a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
index 7e764ca..2de68d3 100644
--- a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
+++ b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
@@ -10,6 +10,52 @@
 LL |     &<A<T> as Foo<T>>::BAR
    |      ^^^^^^^^^^^^^^^^^^^^^
 
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:5
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:5
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:5
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:5
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:6
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |      ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:6
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |      ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr
index f552c8f..4a7dfb1 100644
--- a/tests/ui/consts/const-eval/issue-50814-2.normal.stderr
+++ b/tests/ui/consts/const-eval/issue-50814-2.normal.stderr
@@ -10,6 +10,20 @@
 LL |     &<A<T> as Foo<T>>::BAR
    |      ^^^^^^^^^^^^^^^^^^^^^
 
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:5
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814-2.rs:20:6
+   |
+LL |     &<A<T> as Foo<T>>::BAR
+   |      ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 note: the above error was encountered while instantiating `fn foo::<()>`
   --> $DIR/issue-50814-2.rs:32:22
    |
diff --git a/tests/ui/consts/const-eval/issue-50814.stderr b/tests/ui/consts/const-eval/issue-50814.stderr
index 8d01816..fe0e25b 100644
--- a/tests/ui/consts/const-eval/issue-50814.stderr
+++ b/tests/ui/consts/const-eval/issue-50814.stderr
@@ -26,6 +26,20 @@
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+note: erroneous constant encountered
+  --> $DIR/issue-50814.rs:21:5
+   |
+LL |     &Sum::<U8, U8>::MAX
+   |     ^^^^^^^^^^^^^^^^^^^
+
+note: erroneous constant encountered
+  --> $DIR/issue-50814.rs:21:6
+   |
+LL |     &Sum::<U8, U8>::MAX
+   |      ^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 note: the above error was encountered while instantiating `fn foo::<i32>`
   --> $DIR/issue-50814.rs:26:5
    |
diff --git a/tests/ui/consts/const-eval/issue-85155.stderr b/tests/ui/consts/const-eval/issue-85155.stderr
index a88e959..99836a3 100644
--- a/tests/ui/consts/const-eval/issue-85155.stderr
+++ b/tests/ui/consts/const-eval/issue-85155.stderr
@@ -4,6 +4,14 @@
 LL |         let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero
 
+note: erroneous constant encountered
+  --> $DIR/auxiliary/post_monomorphization_error.rs:19:5
+   |
+LL |     static_assert_imm1!(IMM1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this note originates in the macro `static_assert_imm1` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2>`
   --> $DIR/issue-85155.rs:19:5
    |
diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.rs b/tests/ui/consts/const-eval/unused-broken-const-late.rs
deleted file mode 100644
index c491606..0000000
--- a/tests/ui/consts/const-eval/unused-broken-const-late.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ build-fail
-//@ compile-flags: -O
-//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
-//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
-
-struct PrintName<T>(T);
-impl<T> PrintName<T> {
-    const VOID: () = panic!(); //~ERROR evaluation of `PrintName::<i32>::VOID` failed
-}
-
-fn no_codegen<T>() {
-    // Any function that is called is guaranteed to have all consts that syntactically
-    // appear in its body evaluated, even if they only appear in dead code.
-    if false {
-        let _ = PrintName::<T>::VOID;
-    }
-}
-pub fn main() {
-    no_codegen::<i32>();
-}
diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.stderr b/tests/ui/consts/const-eval/unused-broken-const-late.stderr
deleted file mode 100644
index c2cf2f3..0000000
--- a/tests/ui/consts/const-eval/unused-broken-const-late.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
-  --> $DIR/unused-broken-const-late.rs:8:22
-   |
-LL |     const VOID: () = panic!();
-   |                      ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unused-broken-const-late.rs:8:22
-   |
-   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
new file mode 100644
index 0000000..14a4cb0
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-called-fn.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-called-fn.rs:18:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn called::<i32>`
+  --> $DIR/collect-in-called-fn.rs:23:5
+   |
+LL |     called::<i32>();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
new file mode 100644
index 0000000..14a4cb0
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-called-fn.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-called-fn.rs:18:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn called::<i32>`
+  --> $DIR/collect-in-called-fn.rs:23:5
+   |
+LL |     called::<i32>();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.rs b/tests/ui/consts/required-consts/collect-in-called-fn.rs
new file mode 100644
index 0000000..55133a1
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.rs
@@ -0,0 +1,24 @@
+//@revisions: noopt opt
+//@ build-fail
+//@[opt] compile-flags: -O
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+#[inline(never)]
+fn called<T>() {
+    // Any function that is called is guaranteed to have all consts that syntactically
+    // appear in its body evaluated, even if they only appear in dead code.
+    // This relies on mono-item collection checking `required_consts` in collected functions.
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
new file mode 100644
index 0000000..0bf231d
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-drop.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-drop.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-drop.rs:19:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn <Fail<i32> as std::ops::Drop>::drop`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.rs b/tests/ui/consts/required-consts/collect-in-dead-drop.rs
new file mode 100644
index 0000000..c9ffcec
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.rs
@@ -0,0 +1,33 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but is mentioned implicitly as destructor in dead code in a
+// function that is called. Make sure we still find this error.
+impl<T> Drop for Fail<T> {
+    fn drop(&mut self) {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>(x: T) {
+    if false {
+        let v = Fail(x);
+        // Now it gest dropped implicitly, at the end of this scope.
+    }
+}
+
+pub fn main() {
+    called::<i32>(0);
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
new file mode 100644
index 0000000..8bb99ef
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn.rs:22:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-fn.rs:29:9
+   |
+LL |         not_called::<T>();
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.rs b/tests/ui/consts/required-consts/collect-in-dead-fn.rs
new file mode 100644
index 0000000..9e6b151
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.rs
@@ -0,0 +1,35 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but it is mentioned in dead code in a function that is
+// called. Make sure we still find this error.
+// This relies on mono-item collection checking `required_consts` in functions that syntactically
+// are called in collected functions (even inside dead code).
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        not_called::<T>();
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-forget.rs b/tests/ui/consts/required-consts/collect-in-dead-forget.rs
new file mode 100644
index 0000000..720b7a4
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-forget.rs
@@ -0,0 +1,32 @@
+//@revisions: noopt opt
+//@build-pass
+//@[opt] compile-flags: -O
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!();
+}
+
+// This function is not actually called, but is mentioned implicitly as destructor in dead code in a
+// function that is called. Make sure we still find this error.
+impl<T> Drop for Fail<T> {
+    fn drop(&mut self) {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>(x: T) {
+    if false {
+        let v = Fail(x);
+        std::mem::forget(v);
+        // Now the destructor never gets "mentioned" so this build should *not* fail.
+        // IOW, this demonstrates that we are using a post-drop-elab notion of "mentioned".
+    }
+}
+
+pub fn main() {
+    called::<i32>(0);
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
new file mode 100644
index 0000000..5b1df78
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-move.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-move.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-move.rs:19:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn <Fail<i32> as std::ops::Drop>::drop`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.rs b/tests/ui/consts/required-consts/collect-in-dead-move.rs
new file mode 100644
index 0000000..f3a6ba8
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.rs
@@ -0,0 +1,33 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but is mentioned implicitly as destructor in dead code in a
+// function that is called. Make sure we still find this error.
+impl<T> Drop for Fail<T> {
+    fn drop(&mut self) {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>(x: T) {
+    if false {
+        let v = Fail(x);
+        drop(v); // move `v` away (and it then gets dropped there so build still fails)
+    }
+}
+
+pub fn main() {
+    called::<i32>(0);
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
new file mode 100644
index 0000000..56b6989
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-vtable.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-vtable.rs:26:21
+   |
+LL |             let _ = Fail::<T>::C;
+   |                     ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn <std::vec::Vec<i32> as MyTrait>::not_called`
+  --> $DIR/collect-in-dead-vtable.rs:35:40
+   |
+LL |         let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
+   |                                        ^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
new file mode 100644
index 0000000..f21a1cc
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
@@ -0,0 +1,41 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+trait MyTrait {
+    fn not_called(&self);
+}
+
+// This function is not actually called, but it is mentioned in a vtable in a function that is
+// called. Make sure we still find this error.
+// This relies on mono-item collection checking `required_consts` in functions that are referenced
+// in vtables that syntactically appear in collected functions (even inside dead code).
+impl<T> MyTrait for Vec<T> {
+    fn not_called(&self) {
+        if false {
+            let _ = Fail::<T>::C;
+        }
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        let v: Vec<T> = Vec::new();
+        let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
new file mode 100644
index 0000000..7530459
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-const-called-fn.rs:16:9
+   |
+LL |         Fail::<T>::C;
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
new file mode 100644
index 0000000..7530459
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-const-called-fn.rs:16:9
+   |
+LL |         Fail::<T>::C;
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
new file mode 100644
index 0000000..c409fae
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
@@ -0,0 +1,24 @@
+//@revisions: noopt opt
+//@[opt] compile-flags: -O
+//! Make sure we error on erroneous consts even if they are unused.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+#[inline(never)]
+const fn no_codegen<T>() {
+    if false {
+        // This bad constant is only used in dead code in a no-codegen function... and yet we still
+        // must make sure that the build fails.
+        // This relies on const-eval evaluating all `required_consts` of `const fn`.
+        Fail::<T>::C; //~ constant
+    }
+}
+
+pub static FOO: () = no_codegen::<i32>();
+
+fn main() {
+    FOO
+}
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
new file mode 100644
index 0000000..491131d
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+   |
+   = note: entering unreachable code
+   |
+note: inside `unreachable_unchecked`
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+note: inside `ub`
+  --> $DIR/interpret-in-promoted.rs:6:5
+   |
+LL |     std::hint::unreachable_unchecked();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `FOO`
+  --> $DIR/interpret-in-promoted.rs:12:28
+   |
+LL |     let _x: &'static () = &ub();
+   |                            ^^^^
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-promoted.rs:12:27
+   |
+LL |     let _x: &'static () = &ub();
+   |                           ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
new file mode 100644
index 0000000..491131d
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+   |
+   = note: entering unreachable code
+   |
+note: inside `unreachable_unchecked`
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+note: inside `ub`
+  --> $DIR/interpret-in-promoted.rs:6:5
+   |
+LL |     std::hint::unreachable_unchecked();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `FOO`
+  --> $DIR/interpret-in-promoted.rs:12:28
+   |
+LL |     let _x: &'static () = &ub();
+   |                            ^^^^
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-promoted.rs:12:27
+   |
+LL |     let _x: &'static () = &ub();
+   |                           ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.rs b/tests/ui/consts/required-consts/interpret-in-promoted.rs
new file mode 100644
index 0000000..9c2cf4e
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.rs
@@ -0,0 +1,15 @@
+//@revisions: noopt opt
+//@[opt] compile-flags: -O
+//! Make sure we error on erroneous consts even if they are unused.
+
+const unsafe fn ub() {
+    std::hint::unreachable_unchecked();
+}
+
+pub const FOO: () = unsafe {
+    // Make sure that this gets promoted and then fails to evaluate, and we deal with that
+    // correctly.
+    let _x: &'static () = &ub(); //~ erroneous constant
+};
+
+fn main() {}
diff --git a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
new file mode 100644
index 0000000..159c944
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-static.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-static.rs:15:9
+   |
+LL |         Fail::<i32>::C;
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
new file mode 100644
index 0000000..159c944
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-static.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-static.rs:15:9
+   |
+LL |         Fail::<i32>::C;
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-static.rs b/tests/ui/consts/required-consts/interpret-in-static.rs
new file mode 100644
index 0000000..559e281
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-static.rs
@@ -0,0 +1,21 @@
+//@revisions: noopt opt
+//@[opt] compile-flags: -O
+//! Make sure we error on erroneous consts even if they are unused.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+pub static FOO: () = {
+    if false {
+        // This bad constant is only used in dead code in a static initializer... and yet we still
+        // must make sure that the build fails.
+        // This relies on const-eval evaluating all `required_consts` of the `static` MIR body.
+        Fail::<i32>::C; //~ constant
+    }
+};
+
+fn main() {
+    FOO
+}
diff --git a/tests/ui/coroutine/resume-arg-late-bound.rs b/tests/ui/coroutine/resume-arg-late-bound.rs
index dd6d318..3c2ab41 100644
--- a/tests/ui/coroutine/resume-arg-late-bound.rs
+++ b/tests/ui/coroutine/resume-arg-late-bound.rs
@@ -13,5 +13,5 @@
         *arg = true;
     };
     test(gen);
-    //~^ ERROR mismatched types
+    //~^ ERROR implementation of `Coroutine` is not general enough
 }
diff --git a/tests/ui/coroutine/resume-arg-late-bound.stderr b/tests/ui/coroutine/resume-arg-late-bound.stderr
index a97cc61..4a4ee08 100644
--- a/tests/ui/coroutine/resume-arg-late-bound.stderr
+++ b/tests/ui/coroutine/resume-arg-late-bound.stderr
@@ -1,17 +1,11 @@
-error[E0308]: mismatched types
+error: implementation of `Coroutine` is not general enough
   --> $DIR/resume-arg-late-bound.rs:15:5
    |
 LL |     test(gen);
-   |     ^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^ implementation of `Coroutine` is not general enough
    |
-   = note: expected trait `for<'a> Coroutine<&'a mut bool>`
-              found trait `Coroutine<&mut bool>`
-note: the lifetime requirement is introduced here
-  --> $DIR/resume-arg-late-bound.rs:8:17
-   |
-LL | fn test(a: impl for<'a> Coroutine<&'a mut bool>) {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:15: 11:31}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Coroutine<&'2 mut bool>`, for some specific lifetime `'2`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/cross-crate/auxiliary/static_init_aux.rs b/tests/ui/cross-crate/auxiliary/static_init_aux.rs
index 5e172ef..dca7087 100644
--- a/tests/ui/cross-crate/auxiliary/static_init_aux.rs
+++ b/tests/ui/cross-crate/auxiliary/static_init_aux.rs
@@ -1,6 +1,8 @@
 pub static V: &u32 = &X;
 pub static F: fn() = f;
 pub static G: fn() = G0;
+pub static H: &(dyn Fn() + Sync) = &h;
+pub static I: fn() = Helper(j).mk();
 
 static X: u32 = 42;
 static G0: fn() = g;
@@ -12,3 +14,22 @@
 fn f() {}
 
 fn g() {}
+
+fn h() {}
+
+#[derive(Copy, Clone)]
+struct Helper<T: Copy>(T);
+
+impl<T: Copy + FnOnce()> Helper<T> {
+    const fn mk(self) -> fn() {
+        i::<T>
+    }
+}
+
+fn i<T: FnOnce()>() {
+    assert_eq!(std::mem::size_of::<T>(), 0);
+    // unsafe to work around the lack of a `Default` impl for function items
+    unsafe { (std::mem::transmute_copy::<(), T>(&()))() }
+}
+
+fn j() {}
diff --git a/tests/ui/cross-crate/static-init.rs b/tests/ui/cross-crate/static-init.rs
index 090ad5f..c4697a1 100644
--- a/tests/ui/cross-crate/static-init.rs
+++ b/tests/ui/cross-crate/static-init.rs
@@ -6,6 +6,8 @@
 static V: &u32 = aux::V;
 static F: fn() = aux::F;
 static G: fn() = aux::G;
+static H: &(dyn Fn() + Sync) = aux::H;
+static I: fn() = aux::I;
 
 fn v() -> *const u32 {
     V
@@ -15,4 +17,6 @@
     assert_eq!(aux::v(), crate::v());
     F();
     G();
+    H();
+    I();
 }
diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs
new file mode 100644
index 0000000..1d946a1
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.rs
@@ -0,0 +1,7 @@
+#![deny(unknown_or_malformed_diagnostic_attributes)]
+
+#[diagnostic::unknown_attribute]
+//~^ERROR unknown diagnostic attribute
+struct Foo;
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr
new file mode 100644
index 0000000..a646d36
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/deny_malformed_attribute.stderr
@@ -0,0 +1,14 @@
+error: unknown diagnostic attribute
+  --> $DIR/deny_malformed_attribute.rs:3:15
+   |
+LL | #[diagnostic::unknown_attribute]
+   |               ^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/deny_malformed_attribute.rs:1:9
+   |
+LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs
new file mode 100644
index 0000000..7f60fb6
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-f128.rs
@@ -0,0 +1,15 @@
+#![allow(unused)]
+
+const A: f128 = 10.0; //~ ERROR the type `f128` is unstable
+
+pub fn main() {
+    let a: f128 = 100.0; //~ ERROR the type `f128` is unstable
+    let b = 0.0f128; //~ ERROR the type `f128` is unstable
+    foo(1.23);
+}
+
+fn foo(a: f128) {} //~ ERROR the type `f128` is unstable
+
+struct Bar {
+    a: f128, //~ ERROR the type `f128` is unstable
+}
diff --git a/tests/ui/feature-gates/feature-gate-f128.stderr b/tests/ui/feature-gates/feature-gate-f128.stderr
new file mode 100644
index 0000000..299375c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-f128.stderr
@@ -0,0 +1,53 @@
+error[E0658]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:3:10
+   |
+LL | const A: f128 = 10.0;
+   |          ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:6:12
+   |
+LL |     let a: f128 = 100.0;
+   |            ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:11:11
+   |
+LL | fn foo(a: f128) {}
+   |           ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:14:8
+   |
+LL |     a: f128,
+   |        ^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f128` is unstable
+  --> $DIR/feature-gate-f128.rs:7:13
+   |
+LL |     let b = 0.0f128;
+   |             ^^^^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f128)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs
new file mode 100644
index 0000000..31d8f87
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-f16.rs
@@ -0,0 +1,15 @@
+#![allow(unused)]
+
+const A: f16 = 10.0; //~ ERROR the type `f16` is unstable
+
+pub fn main() {
+    let a: f16 = 100.0; //~ ERROR the type `f16` is unstable
+    let b = 0.0f16; //~ ERROR the type `f16` is unstable
+    foo(1.23);
+}
+
+fn foo(a: f16) {} //~ ERROR the type `f16` is unstable
+
+struct Bar {
+    a: f16, //~ ERROR the type `f16` is unstable
+}
diff --git a/tests/ui/feature-gates/feature-gate-f16.stderr b/tests/ui/feature-gates/feature-gate-f16.stderr
new file mode 100644
index 0000000..e54b54a
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-f16.stderr
@@ -0,0 +1,53 @@
+error[E0658]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:3:10
+   |
+LL | const A: f16 = 10.0;
+   |          ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:6:12
+   |
+LL |     let a: f16 = 100.0;
+   |            ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:11:11
+   |
+LL | fn foo(a: f16) {}
+   |           ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:14:8
+   |
+LL |     a: f16,
+   |        ^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: the type `f16` is unstable
+  --> $DIR/feature-gate-f16.rs:7:13
+   |
+LL |     let b = 0.0f16;
+   |             ^^^^^^
+   |
+   = note: see issue #116909 <https://github.com/rust-lang/rust/issues/116909> for more information
+   = help: add `#![feature(f16)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr
new file mode 100644
index 0000000..06ffff0
--- /dev/null
+++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr
@@ -0,0 +1,48 @@
+error[E0283]: type annotations needed
+  --> $DIR/ambig-hr-projection-issue-93340.rs:16:5
+   |
+LL |     cmp_eq
+   |     ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq`
+   |
+   = note: cannot satisfy `_: Scalar`
+note: required by a bound in `cmp_eq`
+  --> $DIR/ambig-hr-projection-issue-93340.rs:9:22
+   |
+LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
+   |                      ^^^^^^ required by this bound in `cmp_eq`
+help: consider specifying the generic arguments
+   |
+LL |     cmp_eq::<A, B, O>
+   |           +++++++++++
+
+error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}`
+  --> $DIR/ambig-hr-projection-issue-93340.rs:16:5
+   |
+LL |     cmp_eq
+   |     ^^^^^^
+
+error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(<A as Scalar>::RefType<'a>, <B as Scalar>::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}`
+  --> $DIR/ambig-hr-projection-issue-93340.rs:16:5
+   |
+LL |     cmp_eq
+   |     ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0275]: overflow evaluating the requirement `for<'a, 'b> fn(<O as Scalar>::RefType<'a>, <_ as Scalar>::RefType<'b>) -> _ {cmp_eq::<O, ..., ...>} <: ...`
+  --> $DIR/ambig-hr-projection-issue-93340.rs:14:51
+   |
+LL |   ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
+   |  ___________________________________________________^
+LL | |
+LL | |     cmp_eq
+LL | |
+LL | |
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0275, E0283.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr
new file mode 100644
index 0000000..df2ec4a
--- /dev/null
+++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr
@@ -0,0 +1,20 @@
+error[E0283]: type annotations needed
+  --> $DIR/ambig-hr-projection-issue-93340.rs:16:5
+   |
+LL |     cmp_eq
+   |     ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq`
+   |
+   = note: cannot satisfy `_: Scalar`
+note: required by a bound in `cmp_eq`
+  --> $DIR/ambig-hr-projection-issue-93340.rs:9:22
+   |
+LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
+   |                      ^^^^^^ required by this bound in `cmp_eq`
+help: consider specifying the generic arguments
+   |
+LL |     cmp_eq::<A, B, O>
+   |           +++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs
new file mode 100644
index 0000000..4d8ea9d
--- /dev/null
+++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs
@@ -0,0 +1,22 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+pub trait Scalar: 'static {
+    type RefType<'a>: ScalarRef<'a>;
+}
+
+pub trait ScalarRef<'a>: 'a {}
+
+fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
+    todo!()
+}
+
+fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
+) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
+    //[next]~^ ERROR overflow evaluating the requirement
+    cmp_eq
+    //~^ ERROR type annotations needed
+    //[next]~| ERROR overflow evaluating the requirement
+    //[next]~| ERROR overflow evaluating the requirement
+}
+
+fn main() {}
diff --git a/tests/ui/generic-associated-types/bugs/issue-88382.stderr b/tests/ui/generic-associated-types/bugs/issue-88382.stderr
index 9b06152..0f5e394 100644
--- a/tests/ui/generic-associated-types/bugs/issue-88382.stderr
+++ b/tests/ui/generic-associated-types/bugs/issue-88382.stderr
@@ -1,26 +1,21 @@
-error[E0631]: type mismatch in function arguments
+error[E0283]: type annotations needed
   --> $DIR/issue-88382.rs:26:40
    |
 LL |     do_something(SomeImplementation(), test);
-   |     ------------                       ^^^^ expected due to this
-   |     |
-   |     required by a bound introduced by this call
-...
+   |                                        ^^^^ cannot infer type of the type parameter `I` declared on the function `test`
+   |
+   = note: cannot satisfy `_: Iterable`
+   = help: the trait `Iterable` is implemented for `SomeImplementation`
+note: required by a bound in `test`
+  --> $DIR/issue-88382.rs:29:16
+   |
 LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
-   | ------------------------------------------------- found signature defined here
+   |                ^^^^^^^^ required by this bound in `test`
+help: consider specifying the generic argument
    |
-   = note: expected function signature `for<'a> fn(&'a mut std::iter::Empty<usize>) -> _`
-              found function signature `for<'a, 'b> fn(&'b mut <_ as Iterable>::Iterator<'a>) -> _`
-note: required by a bound in `do_something`
-  --> $DIR/issue-88382.rs:20:48
-   |
-LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
-   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something`
-help: consider wrapping the function in a closure
-   |
-LL |     do_something(SomeImplementation(), |arg0: &mut std::iter::Empty<usize>| test(/* &mut <_ as Iterable>::Iterator<'_> */));
-   |                                        ++++++++++++++++++++++++++++++++++++     ++++++++++++++++++++++++++++++++++++++++++
+LL |     do_something(SomeImplementation(), test::<I>);
+   |                                            +++++
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0631`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/generic-associated-types/issue-93340.rs b/tests/ui/generic-associated-types/rigid-hr-projection-issue-93340.rs
similarity index 80%
rename from tests/ui/generic-associated-types/issue-93340.rs
rename to tests/ui/generic-associated-types/rigid-hr-projection-issue-93340.rs
index 783f8c0..b55ca84 100644
--- a/tests/ui/generic-associated-types/issue-93340.rs
+++ b/tests/ui/generic-associated-types/rigid-hr-projection-issue-93340.rs
@@ -1,3 +1,5 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
 //@ check-pass
 
 pub trait Scalar: 'static {
@@ -12,7 +14,7 @@
 
 fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
 ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
-    cmp_eq
+    cmp_eq::<A, B, O>
 }
 
 fn main() {}
diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.rs b/tests/ui/generics/post_monomorphization_error_backtrace.rs
index 56155ae..2c18f2b 100644
--- a/tests/ui/generics/post_monomorphization_error_backtrace.rs
+++ b/tests/ui/generics/post_monomorphization_error_backtrace.rs
@@ -12,6 +12,9 @@
         //~| NOTE: the evaluated program panicked
     }
     F::<T>::V;
+    //~^NOTE: erroneous constant
+    //~|NOTE: erroneous constant
+    //~|NOTE: duplicate
 }
 
 fn foo<U>() {
diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.stderr b/tests/ui/generics/post_monomorphization_error_backtrace.stderr
index 0d707d8..8a57979 100644
--- a/tests/ui/generics/post_monomorphization_error_backtrace.stderr
+++ b/tests/ui/generics/post_monomorphization_error_backtrace.stderr
@@ -6,8 +6,14 @@
    |
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+note: erroneous constant encountered
+  --> $DIR/post_monomorphization_error_backtrace.rs:14:5
+   |
+LL |     F::<T>::V;
+   |     ^^^^^^^^^
+
 note: the above error was encountered while instantiating `fn assert_zst::<u32>`
-  --> $DIR/post_monomorphization_error_backtrace.rs:18:5
+  --> $DIR/post_monomorphization_error_backtrace.rs:21:5
    |
 LL |     assert_zst::<U>()
    |     ^^^^^^^^^^^^^^^^^
@@ -20,8 +26,16 @@
    |
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+note: erroneous constant encountered
+  --> $DIR/post_monomorphization_error_backtrace.rs:14:5
+   |
+LL |     F::<T>::V;
+   |     ^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 note: the above error was encountered while instantiating `fn assert_zst::<i32>`
-  --> $DIR/post_monomorphization_error_backtrace.rs:18:5
+  --> $DIR/post_monomorphization_error_backtrace.rs:21:5
    |
 LL |     assert_zst::<U>()
    |     ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
index 6b20a82..bb4c2a4 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
@@ -394,17 +394,17 @@
 LL |         match $s { $($t)+ => {}, u128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
+   |            ^ pattern `340282366920938463463374607431768211454_u128..` not covered
    |
    = note: the matched value is of type `u128`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u128..=u128::MAX => todo!() }
-   |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LL |         match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u128.. => todo!() }
+   |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
@@ -754,17 +754,17 @@
 LL |         match $s { $($t)+ => {}, i128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
+   |            ^ pattern `170141183460469231731687303715884105726_i128..` not covered
    |
    = note: the matched value is of type `i128`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i128..=i128::MAX => todo!() }
-   |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LL |         match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i128.. => todo!() }
+   |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
diff --git a/tests/ui/higher-ranked/higher-ranked-lifetime-error.rs b/tests/ui/higher-ranked/higher-ranked-lifetime-error.rs
index aee5db8..f89a37c 100644
--- a/tests/ui/higher-ranked/higher-ranked-lifetime-error.rs
+++ b/tests/ui/higher-ranked/higher-ranked-lifetime-error.rs
@@ -10,5 +10,5 @@
 
 fn main() {
     assert_all::<_, &String>(id);
-    //~^ mismatched types
+    //~^ ERROR implementation of `FnMut` is not general enough
 }
diff --git a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
index c25e731..d7add86 100644
--- a/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
+++ b/tests/ui/higher-ranked/higher-ranked-lifetime-error.stderr
@@ -1,12 +1,11 @@
-error[E0308]: mismatched types
+error: implementation of `FnMut` is not general enough
   --> $DIR/higher-ranked-lifetime-error.rs:12:5
    |
 LL |     assert_all::<_, &String>(id);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnMut` is not general enough
    |
-   = note: expected trait `for<'a> <for<'a> fn(&'a String) -> &'a String {id} as FnMut<(&'a String,)>>`
-              found trait `for<'a> <for<'a> fn(&'a String) -> &'a String {id} as FnMut<(&'a String,)>>`
+   = note: `for<'a> fn(&'a String) -> &'a String {id}` must implement `FnMut<(&String,)>`
+   = note: ...but it actually implements `FnMut<(&'0 String,)>`, for some specific lifetime `'0`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.rs b/tests/ui/higher-ranked/trait-bounds/issue-59311.rs
index 387c78a..4e722dc 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-59311.rs
+++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.rs
@@ -6,17 +6,17 @@
 // an error, but the regression test is here to ensure
 // that it does not ICE. See discussion on #74889 for details.
 
-pub trait T {
+pub trait Trait {
     fn t<F: Fn()>(&self, _: F) {}
 }
 
 pub fn crash<V>(v: &V)
 where
-    for<'a> &'a V: T + 'static,
+    for<'a> &'a V: Trait + 'static,
 {
     v.t(|| {});
-    //~^ ERROR: higher-ranked lifetime error
-    //~| ERROR: higher-ranked lifetime error
+    //~^ ERROR: implementation of `Trait` is not general enough
+    //~| ERROR: implementation of `Trait` is not general enough
     //~| ERROR: higher-ranked lifetime error
 }
 
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
index 3053a29..f8bed86 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
@@ -1,18 +1,20 @@
-error: higher-ranked lifetime error
+error: implementation of `Trait` is not general enough
   --> $DIR/issue-59311.rs:17:5
    |
 LL |     v.t(|| {});
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`
+   = note: `Trait` would have to be implemented for the type `&'a V`
+   = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0`
 
-error: higher-ranked lifetime error
+error: implementation of `Trait` is not general enough
   --> $DIR/issue-59311.rs:17:5
    |
 LL |     v.t(|| {});
-   |     ^^^^^^^^^^
+   |     ^^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = note: could not prove `{closure@$DIR/issue-59311.rs:17:9: 17:11} well-formed`
+   = note: `Trait` would have to be implemented for the type `&'a V`
+   = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: higher-ranked lifetime error
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
index 4bd3b96..a44ed9e 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
@@ -43,9 +43,9 @@
     }
 
     foo(bar, "string", |s| s.len() == 5);
-    //~^ ERROR mismatched types
-    //~| ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
     foo(baz, "string", |s| s.0.len() == 5);
-    //~^ ERROR mismatched types
-    //~| ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
 }
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
index 1cf364a..b2bb417 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -1,79 +1,40 @@
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-71955.rs:45:5
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)`
-              found trait `for<'a> FnOnce(&'a &str)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-71955.rs:45:24
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |                        ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-71955.rs:25:9
-   |
-LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-71955.rs:45:5
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)`
-              found trait `for<'a> FnOnce(&'a &str)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-71955.rs:45:24
-   |
-LL |     foo(bar, "string", |s| s.len() == 5);
-   |                        ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-71955.rs:25:44
-   |
-LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
-   |                                            ^^^^
+   = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-71955.rs:48:5
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)`
-              found trait `for<'a> FnOnce(&'a Wrapper<'_>)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-71955.rs:48:24
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |                        ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-71955.rs:25:9
-   |
-LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-71955.rs:48:5
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)`
-              found trait `for<'a> FnOnce(&'a Wrapper<'_>)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-71955.rs:48:24
-   |
-LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |                        ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-71955.rs:25:44
-   |
-LL |     F2: FnOnce(&<F1 as Parser>::Output) -> bool
-   |                                            ^^^^
+   = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.rs b/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.rs
new file mode 100644
index 0000000..35a6acc
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.rs
@@ -0,0 +1,13 @@
+trait Iterable {
+    type Item;
+    fn iter(&self) -> impl Sized;
+}
+
+// `ty::Error` in a trait ref will silence any missing item errors, but will also
+// prevent the `associated_items` query from being called before def ids are frozen.
+impl Iterable for Missing {
+//~^ ERROR cannot find type `Missing` in this scope
+    fn iter(&self) -> Self::Item {}
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr b/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr
new file mode 100644
index 0000000..c172787
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/ensure-rpitits-are-created-before-freezing.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/ensure-rpitits-are-created-before-freezing.rs:8:19
+   |
+LL | impl Iterable for Missing {
+   |                   ^^^^^^^ not found in this scope
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
index ff265e5..84bc39d 100644
--- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
+++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
@@ -9,6 +9,7 @@
         //~^ ERROR: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied [E0277]
         //~| ERROR: the trait bound `Bar: Foo<u8>` is not satisfied [E0277]
         //~| ERROR: impl has stricter requirements than trait
+        //~| ERROR: the trait bound `F2: Foo<u8>` is not satisfied
         self
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
index 12725c3..fbf82a2 100644
--- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
+++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
@@ -11,6 +11,22 @@
 LL |     fn foo<F2>(self) -> impl Foo<T>;
    |                              ^^^^^^ required by this bound in `Foo::{synthetic#0}`
 
+error[E0277]: the trait bound `F2: Foo<u8>` is not satisfied
+  --> $DIR/return-dont-satisfy-bounds.rs:8:34
+   |
+LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
+   |                                  ^^^^^^^^^^^^ the trait `Foo<u8>` is not implemented for `F2`
+   |
+note: required by a bound in `<Bar as Foo<char>>::foo`
+  --> $DIR/return-dont-satisfy-bounds.rs:8:16
+   |
+LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
+   |                ^^^^^^^ required by this bound in `<Bar as Foo<char>>::foo`
+help: consider further restricting this bound
+   |
+LL |     fn foo<F2: Foo<u8> + Foo<u8>>(self) -> impl Foo<u8> {
+   |                        +++++++++
+
 error[E0276]: impl has stricter requirements than trait
   --> $DIR/return-dont-satisfy-bounds.rs:8:16
    |
@@ -32,7 +48,7 @@
    = help: the trait `Foo<char>` is implemented for `Bar`
    = help: for that trait implementation, expected `char`, found `u8`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0276, E0277.
 For more information about an error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/stranded-opaque.rs b/tests/ui/impl-trait/stranded-opaque.rs
new file mode 100644
index 0000000..c7ab390
--- /dev/null
+++ b/tests/ui/impl-trait/stranded-opaque.rs
@@ -0,0 +1,13 @@
+trait Trait {}
+
+impl Trait for i32 {}
+
+// Since `Assoc` doesn't actually exist, it's "stranded", and won't show up in
+// the list of opaques that may be defined by the function. Make sure we don't
+// ICE in this case.
+fn produce<T>() -> impl Trait<Assoc = impl Trait> {
+    //~^ ERROR associated type `Assoc` not found for `Trait`
+    16
+}
+
+fn main () {}
diff --git a/tests/ui/impl-trait/stranded-opaque.stderr b/tests/ui/impl-trait/stranded-opaque.stderr
new file mode 100644
index 0000000..75f5480
--- /dev/null
+++ b/tests/ui/impl-trait/stranded-opaque.stderr
@@ -0,0 +1,9 @@
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/stranded-opaque.rs:8:31
+   |
+LL | fn produce<T>() -> impl Trait<Assoc = impl Trait> {
+   |                               ^^^^^ associated type `Assoc` not found
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/implied-bounds/gluon_salsa.rs b/tests/ui/implied-bounds/gluon_salsa.rs
index 368fb19..cc6352c 100644
--- a/tests/ui/implied-bounds/gluon_salsa.rs
+++ b/tests/ui/implied-bounds/gluon_salsa.rs
@@ -1,5 +1,6 @@
 //@ check-pass
-// Found in a crater run on #118553
+// Related to Bevy regression #115559, found in
+// a crater run on #118553.
 
 pub trait QueryBase {
     type Db;
@@ -17,11 +18,17 @@
     _marker: Option<&'me ()>,
 }
 
-impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db> // projection is important
-//   ^^^ removing 'me (and in QueryTable) gives a different error
+impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db>
 where
     Q: for<'f> AsyncQueryFunction<'f>,
 {
+    // When borrowchechking this function we normalize `<Q as QueryBase>::Db` in the
+    // function signature to `<Self as QueryFunction<'?x>>::SendDb`, where `'?x` is an
+    // unconstrained region variable. We then addd `<Self as QueryFunction<'?x>>::SendDb: 'a`
+    // as an implied bound. We currently a structural equality to decide whether this bound
+    // should be used to prove the bound  `<Self as QueryFunction<'?x>>::SendDb: 'a`. For this
+    // to work we may have to structurally resolve regions as the actually used vars may
+    // otherwise be semantically equal but structurally different.
     pub fn get_async<'a>(&'a mut self) {
         panic!();
     }
diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr
index fc0b6cc..7331c7f 100644
--- a/tests/ui/inline-const/const-expr-generic-err.stderr
+++ b/tests/ui/inline-const/const-expr-generic-err.stderr
@@ -6,6 +6,12 @@
    |
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+note: erroneous constant encountered
+  --> $DIR/const-expr-generic-err.rs:5:5
+   |
+LL |     const { assert!(std::mem::size_of::<T>() == 0); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 note: the above error was encountered while instantiating `fn foo::<i32>`
   --> $DIR/const-expr-generic-err.rs:13:5
    |
@@ -18,6 +24,20 @@
 LL |     const { N - 1 }
    |             ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
+note: erroneous constant encountered
+  --> $DIR/const-expr-generic-err.rs:9:5
+   |
+LL |     const { N - 1 }
+   |     ^^^^^^^^^^^^^^^
+
+note: erroneous constant encountered
+  --> $DIR/const-expr-generic-err.rs:9:5
+   |
+LL |     const { N - 1 }
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 note: the above error was encountered while instantiating `fn bar::<0>`
   --> $DIR/const-expr-generic-err.rs:14:5
    |
diff --git a/tests/ui/inline-const/required-const.stderr b/tests/ui/inline-const/required-const.stderr
index cd86020..2a13d18 100644
--- a/tests/ui/inline-const/required-const.stderr
+++ b/tests/ui/inline-const/required-const.stderr
@@ -6,6 +6,12 @@
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+note: erroneous constant encountered
+  --> $DIR/required-const.rs:7:9
+   |
+LL |         const { panic!() }
+   |         ^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/lifetimes/issue-105675.rs b/tests/ui/lifetimes/issue-105675.rs
index 58d8be8..2e2eaca 100644
--- a/tests/ui/lifetimes/issue-105675.rs
+++ b/tests/ui/lifetimes/issue-105675.rs
@@ -3,12 +3,12 @@
 fn main() {
     let f = | _ , y: &u32 , z | ();
     thing(f);
-    //~^ ERROR mismatched types
-    //~^^ ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~^^ ERROR implementation of `FnOnce` is not general enough
     let f = | x, y: _  , z: u32 | ();
     thing(f);
-    //~^ ERROR mismatched types
-    //~^^ ERROR mismatched types
-    //~^^^ ERROR implementation of `FnOnce` is not general enough
-    //~^^^^ ERROR implementation of `FnOnce` is not general enough
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
 }
diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr
index f1fa5a5..4b3d0e8 100644
--- a/tests/ui/lifetimes/issue-105675.stderr
+++ b/tests/ui/lifetimes/issue-105675.stderr
@@ -1,91 +1,21 @@
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-105675.rs:5:5
    |
 LL |     thing(f);
-   |     ^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
-              found trait `for<'a> FnOnce(&u32, &'a u32, u32)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-105675.rs:4:13
-   |
-LL |     let f = | _ , y: &u32 , z | ();
-   |             ^^^^^^^^^^^^^^^^^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-105675.rs:1:18
-   |
-LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     let f = |_: &_, y: &u32, z| ();
-   |             ~~~~~~~~~~~~~~~~~~~
+   = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-105675.rs:5:5
    |
 LL |     thing(f);
-   |     ^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
-              found trait `for<'a> FnOnce(&u32, &'a u32, u32)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-105675.rs:4:13
-   |
-LL |     let f = | _ , y: &u32 , z | ();
-   |             ^^^^^^^^^^^^^^^^^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-105675.rs:1:18
-   |
-LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0308]: mismatched types
-  --> $DIR/issue-105675.rs:9:5
-   |
-LL |     thing(f);
-   |     ^^^^^^^^ one type is more general than the other
-   |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
-              found trait `FnOnce(&u32, &u32, u32)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-105675.rs:8:13
-   |
-LL |     let f = | x, y: _  , z: u32 | ();
-   |             ^^^^^^^^^^^^^^^^^^^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-105675.rs:1:18
-   |
-LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     let f = |x: &_, y: &_, z: u32| ();
-   |             ~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0308]: mismatched types
-  --> $DIR/issue-105675.rs:9:5
-   |
-LL |     thing(f);
-   |     ^^^^^^^^ one type is more general than the other
-   |
-   = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)`
-              found trait `FnOnce(&u32, &u32, u32)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-105675.rs:8:13
-   |
-LL |     let f = | x, y: _  , z: u32 | ();
-   |             ^^^^^^^^^^^^^^^^^^^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-105675.rs:1:18
-   |
-LL | fn thing(x: impl FnOnce(&u32, &u32, u32)) {}
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: consider specifying the type of the closure parameters
-   |
-LL |     let f = |x: &_, y: &_, z: u32| ();
-   |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-105675.rs:9:5
@@ -105,6 +35,25 @@
    = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2`
 
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-105675.rs:9:5
+   |
+LL |     thing(f);
+   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-105675.rs:9:5
+   |
+LL |     thing(f);
+   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs
index 85eeb5d..eab436f 100644
--- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs
+++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs
@@ -7,6 +7,7 @@
 //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
 //~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
 //~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
+//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
 where
 F:,
 for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr
index 578ba14..e9f97d1 100644
--- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr
+++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr
@@ -5,7 +5,7 @@
 LL | |
 LL | |
 LL | |
-LL | | where
+...  |
 LL | | F:,
 LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
    | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
@@ -27,7 +27,7 @@
 LL | |
 LL | |
 LL | |
-LL | | where
+...  |
 LL | | F:,
 LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
    | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
@@ -35,7 +35,22 @@
    = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
 
 error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
-  --> $DIR/issue-76168-hr-outlives-3.rs:13:1
+  --> $DIR/issue-76168-hr-outlives-3.rs:6:1
+   |
+LL | / async fn wrapper<F>(f: F)
+LL | |
+LL | |
+LL | |
+...  |
+LL | | F:,
+LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
+   | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32`
+   |
+   = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
+  --> $DIR/issue-76168-hr-outlives-3.rs:14:1
    |
 LL | / {
 LL | |
@@ -46,6 +61,6 @@
    |
    = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lifetimes/issue-79187-2.rs b/tests/ui/lifetimes/issue-79187-2.rs
index fff92c3..9d7f17e 100644
--- a/tests/ui/lifetimes/issue-79187-2.rs
+++ b/tests/ui/lifetimes/issue-79187-2.rs
@@ -7,7 +7,7 @@
 fn main() {
     take_foo(|a| a);
     //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR mismatched types
+    //~| ERROR implementation of `Fn` is not general enough
     take_foo(|a: &i32| a);
     //~^ ERROR lifetime may not live long enough
     //~| ERROR mismatched types
diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr
index e8115bb..78f6ce8 100644
--- a/tests/ui/lifetimes/issue-79187-2.stderr
+++ b/tests/ui/lifetimes/issue-79187-2.stderr
@@ -25,28 +25,14 @@
    = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/issue-79187-2.rs:8:5
    |
 LL |     take_foo(|a| a);
-   |     ^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a> Fn(&'a i32)`
-              found trait `Fn(&i32)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-79187-2.rs:8:14
-   |
-LL |     take_foo(|a| a);
-   |              ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-79187-2.rs:5:21
-   |
-LL | fn take_foo(_: impl Foo) {}
-   |                     ^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     take_foo(|a: &_| a);
-   |              ~~~~~~~
+   = note: closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 i32,)>`, for some specific lifetime `'2`
 
 error[E0308]: mismatched types
   --> $DIR/issue-79187-2.rs:11:5
diff --git a/tests/ui/lifetimes/issue-79187.rs b/tests/ui/lifetimes/issue-79187.rs
index 8e13045..a8829bd 100644
--- a/tests/ui/lifetimes/issue-79187.rs
+++ b/tests/ui/lifetimes/issue-79187.rs
@@ -3,6 +3,6 @@
 fn main() {
     let f = |_| ();
     thing(f);
-    //~^ ERROR mismatched types
-    //~^^ ERROR implementation of `FnOnce` is not general enough
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
 }
diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr
index 14bdfe7..8adde8d 100644
--- a/tests/ui/lifetimes/issue-79187.stderr
+++ b/tests/ui/lifetimes/issue-79187.stderr
@@ -1,26 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-79187.rs:5:5
-   |
-LL |     thing(f);
-   |     ^^^^^^^^ one type is more general than the other
-   |
-   = note: expected trait `for<'a> FnOnce(&'a u32)`
-              found trait `FnOnce(&u32)`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/issue-79187.rs:4:13
-   |
-LL |     let f = |_| ();
-   |             ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/issue-79187.rs:1:18
-   |
-LL | fn thing(x: impl FnOnce(&u32)) {}
-   |                  ^^^^^^^^^^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     let f = |_: &_| ();
-   |             ~~~~~~~
-
 error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-79187.rs:5:5
    |
@@ -30,6 +7,15 @@
    = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2`
 
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-79187.rs:5:5
+   |
+LL |     thing(f);
+   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.rs b/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
index f17e0a6..b02e38b 100644
--- a/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
+++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.rs
@@ -13,6 +13,6 @@
     //~^ ERROR the parameter type
     //~| ERROR the parameter type
     //~| ERROR the parameter type
-    //~| ERROR mismatched types
     //~| ERROR implementation of `FnOnce` is not general
+    //~| ERROR implementation of `Fn` is not general enough
 }
diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
index beb838d..4dada6f 100644
--- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr
@@ -42,19 +42,14 @@
 LL | fn g<T: 'static>(data: &[T]) {
    |       +++++++++
 
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/issue_74400.rs:12:5
    |
 LL |     f(data, identity)
-   |     ^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a> Fn(&'a T)`
-              found trait `Fn(&T)`
-note: the lifetime requirement is introduced here
-  --> $DIR/issue_74400.rs:8:34
-   |
-LL | fn f<T, S>(data: &[T], key: impl Fn(&T) -> S) {
-   |                                  ^^^^^^^^^^^
+   = note: `fn(&'2 T) -> &'2 T {identity::<&'2 T>}` must implement `Fn<(&'1 T,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 T,)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/issue_74400.rs:12:5
@@ -67,5 +62,4 @@
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0308, E0310.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/lint/lint-qualification.fixed b/tests/ui/lint/lint-qualification.fixed
index 2b1f8b5..6fe6ba2 100644
--- a/tests/ui/lint/lint-qualification.fixed
+++ b/tests/ui/lint/lint-qualification.fixed
@@ -1,5 +1,6 @@
 //@ run-rustfix
 #![deny(unused_qualifications)]
+#![deny(unused_imports)]
 #![allow(deprecated, dead_code)]
 
 mod foo {
@@ -21,8 +22,10 @@
     //~^ ERROR: unnecessary qualification
     //~| ERROR: unnecessary qualification
 
-    use std::fmt;
-    let _: fmt::Result = Ok(()); //~ ERROR: unnecessary qualification
+    
+    //~^ ERROR: unused import: `std::fmt`
+    let _: std::fmt::Result = Ok(());
+    // don't report unnecessary qualification because fix(#122373) for issue #121331
 
     let _ = <bool as Default>::default(); // issue #121999
     //~^ ERROR: unnecessary qualification
diff --git a/tests/ui/lint/lint-qualification.rs b/tests/ui/lint/lint-qualification.rs
index 002fdbf..19d339b 100644
--- a/tests/ui/lint/lint-qualification.rs
+++ b/tests/ui/lint/lint-qualification.rs
@@ -1,5 +1,6 @@
 //@ run-rustfix
 #![deny(unused_qualifications)]
+#![deny(unused_imports)]
 #![allow(deprecated, dead_code)]
 
 mod foo {
@@ -22,7 +23,9 @@
     //~| ERROR: unnecessary qualification
 
     use std::fmt;
-    let _: std::fmt::Result = Ok(()); //~ ERROR: unnecessary qualification
+    //~^ ERROR: unused import: `std::fmt`
+    let _: std::fmt::Result = Ok(());
+    // don't report unnecessary qualification because fix(#122373) for issue #121331
 
     let _ = <bool as ::std::default::Default>::default(); // issue #121999
     //~^ ERROR: unnecessary qualification
diff --git a/tests/ui/lint/lint-qualification.stderr b/tests/ui/lint/lint-qualification.stderr
index 8dddcf2..9e5c9b2 100644
--- a/tests/ui/lint/lint-qualification.stderr
+++ b/tests/ui/lint/lint-qualification.stderr
@@ -1,5 +1,5 @@
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:11:5
+  --> $DIR/lint-qualification.rs:12:5
    |
 LL |     foo::bar();
    |     ^^^^^^^^
@@ -16,7 +16,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:12:5
+  --> $DIR/lint-qualification.rs:13:5
    |
 LL |     crate::foo::bar();
    |     ^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:17:13
+  --> $DIR/lint-qualification.rs:18:13
    |
 LL |     let _ = std::string::String::new();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:18:13
+  --> $DIR/lint-qualification.rs:19:13
    |
 LL |     let _ = ::std::env::current_dir();
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:20:12
+  --> $DIR/lint-qualification.rs:21:12
    |
 LL |     let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
    |            ^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +64,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:20:36
+  --> $DIR/lint-qualification.rs:21:36
    |
 LL |     let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,20 +75,20 @@
 LL +     let _: std::vec::Vec<String> = Vec::<String>::new();
    |
 
-error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:25:12
+error: unused import: `std::fmt`
+  --> $DIR/lint-qualification.rs:25:9
    |
-LL |     let _: std::fmt::Result = Ok(());
-   |            ^^^^^^^^^^^^^^^^
+LL |     use std::fmt;
+   |         ^^^^^^^^
    |
-help: remove the unnecessary path segments
+note: the lint level is defined here
+  --> $DIR/lint-qualification.rs:3:9
    |
-LL -     let _: std::fmt::Result = Ok(());
-LL +     let _: fmt::Result = Ok(());
-   |
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
 
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:27:13
+  --> $DIR/lint-qualification.rs:30:13
    |
 LL |     let _ = <bool as ::std::default::Default>::default(); // issue #121999
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed
new file mode 100644
index 0000000..d554bbf
--- /dev/null
+++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed
@@ -0,0 +1,50 @@
+//@ run-rustfix
+//@ edition:2021
+#![deny(unused_qualifications)]
+#![deny(unused_imports)]
+#![feature(coroutines, coroutine_trait)]
+
+use std::ops::{
+    Coroutine,
+    CoroutineState::{self},
+    //~^ ERROR unused import: `*`
+};
+use std::pin::Pin;
+
+#[allow(dead_code)]
+fn finish<T>(mut amt: usize, mut t: T) -> T::Return
+    where T: Coroutine<(), Yield = ()> + Unpin,
+{
+    loop {
+        match Pin::new(&mut t).resume(()) {
+            CoroutineState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
+            CoroutineState::Complete(ret) => {
+                assert_eq!(amt, 0);
+                return ret
+            }
+        }
+    }
+}
+
+
+mod foo {
+    pub fn bar() {}
+}
+
+pub fn main() {
+
+    use foo::bar;
+    bar();
+    //~^ ERROR unnecessary qualification
+    bar();
+
+    // The item `use std::string::String` is imported redundantly.
+    // Suppress `unused_imports` reporting, otherwise the fixed file will report an error
+    #[allow(unused_imports)]
+    use std::string::String;
+    let s = String::new();
+    let y = std::string::String::new();
+    // unnecessary qualification
+    println!("{} {}", s, y);
+
+}
diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs
new file mode 100644
index 0000000..4d79f5a
--- /dev/null
+++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs
@@ -0,0 +1,50 @@
+//@ run-rustfix
+//@ edition:2021
+#![deny(unused_qualifications)]
+#![deny(unused_imports)]
+#![feature(coroutines, coroutine_trait)]
+
+use std::ops::{
+    Coroutine,
+    CoroutineState::{self, *},
+    //~^ ERROR unused import: `*`
+};
+use std::pin::Pin;
+
+#[allow(dead_code)]
+fn finish<T>(mut amt: usize, mut t: T) -> T::Return
+    where T: Coroutine<(), Yield = ()> + Unpin,
+{
+    loop {
+        match Pin::new(&mut t).resume(()) {
+            CoroutineState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
+            CoroutineState::Complete(ret) => {
+                assert_eq!(amt, 0);
+                return ret
+            }
+        }
+    }
+}
+
+
+mod foo {
+    pub fn bar() {}
+}
+
+pub fn main() {
+
+    use foo::bar;
+    foo::bar();
+    //~^ ERROR unnecessary qualification
+    bar();
+
+    // The item `use std::string::String` is imported redundantly.
+    // Suppress `unused_imports` reporting, otherwise the fixed file will report an error
+    #[allow(unused_imports)]
+    use std::string::String;
+    let s = String::new();
+    let y = std::string::String::new();
+    // unnecessary qualification
+    println!("{} {}", s, y);
+
+}
diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr
new file mode 100644
index 0000000..52ed13e
--- /dev/null
+++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.stderr
@@ -0,0 +1,31 @@
+error: unused import: `*`
+  --> $DIR/lint-unnecessary-qualification-issue-121331.rs:9:28
+   |
+LL |     CoroutineState::{self, *},
+   |                            ^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unnecessary-qualification-issue-121331.rs:4:9
+   |
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+error: unnecessary qualification
+  --> $DIR/lint-unnecessary-qualification-issue-121331.rs:37:5
+   |
+LL |     foo::bar();
+   |     ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unnecessary-qualification-issue-121331.rs:3:9
+   |
+LL | #![deny(unused_qualifications)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+help: remove the unnecessary path segments
+   |
+LL -     foo::bar();
+LL +     bar();
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr
index 452cba6..e52e095 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr
@@ -24,7 +24,7 @@
    |                        expected due to this
    |
    = note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
-              found closure signature `for<'a, 'b, 'c> fn(&'a &'b &'c i32) -> _`
+              found closure signature `fn(&&&i32) -> _`
 note: required by a bound in `find`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 help: consider adjusting the signature so it does not borrow its argument
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch.rs
index e73a33d..55a4a0b 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch.rs
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.rs
@@ -8,7 +8,7 @@
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
     baz(f);
-    //~^ ERROR: mismatched types
+    //~^ ERROR: implementation of `FnOnce` is not general enough
     //~| ERROR: borrowed data escapes
     //~| ERROR: not general enough
 }
diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
index e63d3f6..abc5d15 100644
--- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -24,7 +24,7 @@
    |              expected due to this
    |
    = note: expected closure signature `fn(&(u32, u32)) -> _`
-              found closure signature `for<'a> fn(&'a (u16, u16)) -> _`
+              found closure signature `fn(&(u16, u16)) -> _`
 note: required by a bound in `map`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
@@ -63,19 +63,14 @@
 LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
    |           ^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^^^^ one type is more general than the other
+   |     ^^^^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a> Fn(*mut &'a u32)`
-              found trait `Fn(*mut &u32)`
-note: the lifetime requirement is introduced here
-  --> $DIR/closure-arg-type-mismatch.rs:8:11
-   |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ^^^^^^^^^^^^^
+   = note: `fn(*mut &'2 u32)` must implement `Fn<(*mut &'1 u32,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(*mut &'2 u32,)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/closure-arg-type-mismatch.rs:10:5
@@ -88,5 +83,5 @@
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0308, E0521, E0631.
-For more information about an error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0521, E0631.
+For more information about an error, try `rustc --explain E0521`.
diff --git a/tests/ui/mismatched_types/closure-mismatch.rs b/tests/ui/mismatched_types/closure-mismatch.rs
index 4eb3349..efaed4d 100644
--- a/tests/ui/mismatched_types/closure-mismatch.rs
+++ b/tests/ui/mismatched_types/closure-mismatch.rs
@@ -7,8 +7,8 @@
 fn main() {
     baz(|_| ());
     //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR mismatched types
+    //~| ERROR implementation of `Fn` is not general enough
     baz(|x| ());
     //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR mismatched types
+    //~| ERROR implementation of `Fn` is not general enough
 }
diff --git a/tests/ui/mismatched_types/closure-mismatch.stderr b/tests/ui/mismatched_types/closure-mismatch.stderr
index 74033c1..802110c 100644
--- a/tests/ui/mismatched_types/closure-mismatch.stderr
+++ b/tests/ui/mismatched_types/closure-mismatch.stderr
@@ -7,28 +7,14 @@
    = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/closure-mismatch.rs:8:5
    |
 LL |     baz(|_| ());
-   |     ^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a> Fn(&'a ())`
-              found trait `Fn(&())`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/closure-mismatch.rs:8:9
-   |
-LL |     baz(|_| ());
-   |         ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/closure-mismatch.rs:5:11
-   |
-LL | fn baz<T: Foo>(_: T) {}
-   |           ^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     baz(|_: &_| ());
-   |         ~~~~~~~
+   = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/closure-mismatch.rs:11:5
@@ -39,29 +25,14 @@
    = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/closure-mismatch.rs:11:5
    |
 LL |     baz(|x| ());
-   |     ^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a> Fn(&'a ())`
-              found trait `Fn(&())`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/closure-mismatch.rs:11:9
-   |
-LL |     baz(|x| ());
-   |         ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/closure-mismatch.rs:5:11
-   |
-LL | fn baz<T: Foo>(_: T) {}
-   |           ^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     baz(|x: &_| ());
-   |         ~~~~~~~
+   = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/fn-variance-1.stderr b/tests/ui/mismatched_types/fn-variance-1.stderr
index fdb2e6f..ed450d8 100644
--- a/tests/ui/mismatched_types/fn-variance-1.stderr
+++ b/tests/ui/mismatched_types/fn-variance-1.stderr
@@ -10,7 +10,7 @@
    |     required by a bound introduced by this call
    |
    = note: expected function signature `fn(&{integer}) -> _`
-              found function signature `for<'a> fn(&'a mut isize) -> _`
+              found function signature `fn(&mut isize) -> _`
 note: required by a bound in `apply`
   --> $DIR/fn-variance-1.rs:5:37
    |
@@ -33,7 +33,7 @@
    |     required by a bound introduced by this call
    |
    = note: expected function signature `fn(&mut {integer}) -> _`
-              found function signature `for<'a> fn(&'a isize) -> _`
+              found function signature `fn(&isize) -> _`
 note: required by a bound in `apply`
   --> $DIR/fn-variance-1.rs:5:37
    |
diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr
index 6d23319..ffaa276 100644
--- a/tests/ui/mismatched_types/issue-36053-2.stderr
+++ b/tests/ui/mismatched_types/issue-36053-2.stderr
@@ -7,7 +7,7 @@
    |                                expected due to this
    |
    = note: expected closure signature `for<'a> fn(&'a &_) -> _`
-              found closure signature `for<'a> fn(&'a _) -> _`
+              found closure signature `fn(&_) -> _`
 note: required by a bound in `filter`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 help: consider adjusting the signature so it borrows its argument
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
index 0ed5746..0b89438 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
@@ -10,7 +10,7 @@
    |                                                    required by a bound introduced by this call
    |
    = note: expected function signature `fn({integer}) -> _`
-              found function signature `for<'a> fn(&'a i32) -> _`
+              found function signature `fn(&i32) -> _`
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
index 1ac057a..99c9028 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
@@ -10,7 +10,7 @@
    |                               required by a bound introduced by this call
    |
    = note: expected function signature `fn(String) -> _`
-              found function signature `for<'a, 'b> fn(&'a &'b str) -> _`
+              found function signature `fn(&&str) -> _`
 note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
@@ -69,7 +69,7 @@
    |                                    required by a bound introduced by this call
    |
    = note: expected function signature `fn(TypeWithoutDeref) -> _`
-              found function signature `for<'a, 'b> fn(&'a &'b str) -> _`
+              found function signature `fn(&&str) -> _`
 note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr
index 1702a7f..306c412 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr
@@ -10,7 +10,7 @@
    |                                           required by a bound introduced by this call
    |
    = note: expected function signature `fn(String) -> _`
-              found function signature `for<'a> fn(&'a str) -> _`
+              found function signature `fn(&str) -> _`
 note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
@@ -34,7 +34,7 @@
    |                                                   required by a bound introduced by this call
    |
    = note: expected function signature `fn(String) -> _`
-              found function signature `for<'a> fn(&'a str) -> _`
+              found function signature `fn(&str) -> _`
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
@@ -58,7 +58,7 @@
    |                                                   required by a bound introduced by this call
    |
    = note: expected function signature `fn(String) -> _`
-              found function signature `for<'a> fn(&'a mut str) -> _`
+              found function signature `fn(&mut str) -> _`
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
@@ -82,7 +82,7 @@
    |                               required by a bound introduced by this call
    |
    = note: expected function signature `fn(String) -> _`
-              found function signature `for<'a> fn(&'a _) -> _`
+              found function signature `fn(&_) -> _`
 note: required by a bound in `Option::<T>::and_then`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.rs b/tests/ui/nll/missing-universe-cause-issue-114907.rs
index 9c69c6b..a3eb5fc 100644
--- a/tests/ui/nll/missing-universe-cause-issue-114907.rs
+++ b/tests/ui/nll/missing-universe-cause-issue-114907.rs
@@ -31,8 +31,8 @@
 fn main() {
     let callback = |_| {};
     accept(callback);
-    //~^ ERROR mismatched types
-    //~| ERROR mismatched types
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR higher-ranked subtype error
diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr
index a616d29..26ad1ef 100644
--- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr
+++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr
@@ -1,26 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/missing-universe-cause-issue-114907.rs:33:5
-   |
-LL |     accept(callback);
-   |     ^^^^^^^^^^^^^^^^ one type is more general than the other
-   |
-   = note: expected trait `for<'a> FnOnce(&'a ())`
-              found trait `FnOnce(&())`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/missing-universe-cause-issue-114907.rs:32:20
-   |
-LL |     let callback = |_| {};
-   |                    ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/missing-universe-cause-issue-114907.rs:27:14
-   |
-LL | fn accept<C: FnOnce(&())>(_: C) -> Handshake<HandshakeCallback<C>> {
-   |              ^^^^^^^^^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     let callback = |_: &_| {};
-   |                    ~~~~~~~
-
 error: implementation of `FnOnce` is not general enough
   --> $DIR/missing-universe-cause-issue-114907.rs:33:5
    |
@@ -40,28 +17,25 @@
    = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0308]: mismatched types
+error: implementation of `FnOnce` is not general enough
   --> $DIR/missing-universe-cause-issue-114907.rs:33:5
    |
 LL |     accept(callback);
-   |     ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-   = note: expected trait `for<'a> FnOnce(&'a ())`
-              found trait `FnOnce(&())`
-note: this closure does not fulfill the lifetime requirements
-  --> $DIR/missing-universe-cause-issue-114907.rs:32:20
+   = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/missing-universe-cause-issue-114907.rs:33:5
    |
-LL |     let callback = |_| {};
-   |                    ^^^
-note: the lifetime requirement is introduced here
-  --> $DIR/missing-universe-cause-issue-114907.rs:20:21
+LL |     accept(callback);
+   |     ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
    |
-LL | struct Handshake<R: Role> {
-   |                     ^^^^
-help: consider specifying the type of the closure parameters
-   |
-LL |     let callback = |_: &_| {};
-   |                    ~~~~~~~
+   = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: higher-ranked subtype error
   --> $DIR/missing-universe-cause-issue-114907.rs:33:21
@@ -79,4 +53,3 @@
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/f16-f128.rs b/tests/ui/parser/f16-f128.rs
deleted file mode 100644
index 4f31dcc..0000000
--- a/tests/ui/parser/f16-f128.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Make sure we don't ICE while incrementally adding f16 and f128 support
-
-mod f16_checks {
-    const A: f16 = 10.0; //~ ERROR cannot find type `f16` in this scope
-
-    pub fn main() {
-        let a: f16 = 100.0; //~ ERROR cannot find type `f16` in this scope
-        let b = 0.0f16; //~ ERROR invalid width `16` for float literal
-
-        foo(1.23);
-    }
-
-    fn foo(a: f16) {} //~ ERROR cannot find type `f16` in this scope
-
-    struct Bar {
-        a: f16, //~ ERROR cannot find type `f16` in this scope
-    }
-}
-
-mod f128_checks {
-    const A: f128 = 10.0; //~ ERROR cannot find type `f128` in this scope
-
-    pub fn main() {
-        let a: f128 = 100.0; //~ ERROR cannot find type `f128` in this scope
-        let b = 0.0f128; //~ ERROR invalid width `128` for float literal
-
-        foo(1.23);
-    }
-
-    fn foo(a: f128) {} //~ ERROR cannot find type `f128` in this scope
-
-    struct Bar {
-        a: f128, //~ ERROR cannot find type `f128` in this scope
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/parser/f16-f128.stderr b/tests/ui/parser/f16-f128.stderr
deleted file mode 100644
index d3f2227..0000000
--- a/tests/ui/parser/f16-f128.stderr
+++ /dev/null
@@ -1,67 +0,0 @@
-error[E0412]: cannot find type `f16` in this scope
-  --> $DIR/f16-f128.rs:4:14
-   |
-LL |     const A: f16 = 10.0;
-   |              ^^^ help: a builtin type with a similar name exists: `i16`
-
-error[E0412]: cannot find type `f16` in this scope
-  --> $DIR/f16-f128.rs:7:16
-   |
-LL |         let a: f16 = 100.0;
-   |                ^^^ help: a builtin type with a similar name exists: `i16`
-
-error[E0412]: cannot find type `f16` in this scope
-  --> $DIR/f16-f128.rs:13:15
-   |
-LL |     fn foo(a: f16) {}
-   |               ^^^ help: a builtin type with a similar name exists: `i16`
-
-error[E0412]: cannot find type `f16` in this scope
-  --> $DIR/f16-f128.rs:16:12
-   |
-LL |         a: f16,
-   |            ^^^ help: a builtin type with a similar name exists: `i16`
-
-error[E0412]: cannot find type `f128` in this scope
-  --> $DIR/f16-f128.rs:21:14
-   |
-LL |     const A: f128 = 10.0;
-   |              ^^^^ help: a builtin type with a similar name exists: `i128`
-
-error[E0412]: cannot find type `f128` in this scope
-  --> $DIR/f16-f128.rs:24:16
-   |
-LL |         let a: f128 = 100.0;
-   |                ^^^^ help: a builtin type with a similar name exists: `i128`
-
-error[E0412]: cannot find type `f128` in this scope
-  --> $DIR/f16-f128.rs:30:15
-   |
-LL |     fn foo(a: f128) {}
-   |               ^^^^ help: a builtin type with a similar name exists: `i128`
-
-error[E0412]: cannot find type `f128` in this scope
-  --> $DIR/f16-f128.rs:33:12
-   |
-LL |         a: f128,
-   |            ^^^^ help: a builtin type with a similar name exists: `i128`
-
-error: invalid width `16` for float literal
-  --> $DIR/f16-f128.rs:8:17
-   |
-LL |         let b = 0.0f16;
-   |                 ^^^^^^
-   |
-   = help: valid widths are 32 and 64
-
-error: invalid width `128` for float literal
-  --> $DIR/f16-f128.rs:25:17
-   |
-LL |         let b = 0.0f128;
-   |                 ^^^^^^^
-   |
-   = help: valid widths are 32 and 64
-
-error: aborting due to 10 previous errors
-
-For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index 25838fb..16a93a0 100644
--- a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -13,7 +13,7 @@
    |              ^^   ------ value borrowed here after move
    |              |
    |              value moved into `_z` here
-   |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
+   |              move occurs because `_z` has type `X`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -35,7 +35,7 @@
    |              ^^   ---------- value borrowed here after move
    |              |
    |              value moved into `_z` here
-   |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
+   |              move occurs because `_z` has type `X`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
index 815a4ad..ea04d4b 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -5,7 +5,7 @@
    |         ^   ----- value borrowed here after move
    |         |
    |         value moved into `a` here
-   |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index fd7a5138..25c940a 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -5,7 +5,7 @@
    |         ^   ----- value borrowed here after move
    |         |
    |         value moved into `a` here
-   |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -20,7 +20,7 @@
    |         |            |
    |         |            value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `(U, U)`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -34,7 +34,7 @@
    |              ^^^^^   --------- value borrowed here after move
    |              |
    |              value moved into `b` here
-   |              move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |              move occurs because `b` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -48,7 +48,7 @@
    |                                 ^   ----- value borrowed here after move
    |                                 |
    |                                 value moved into `d` here
-   |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |                                 move occurs because `d` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -63,7 +63,7 @@
    |         |    |
    |         |    value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `[U; 2]`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -77,7 +77,7 @@
    |         ^   ----- value borrowed here after move
    |         |
    |         value moved into `a` here
-   |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -92,7 +92,7 @@
    |         |            |
    |         |            value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `(U, U)`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -106,7 +106,7 @@
    |              ^^^^^   --------- value borrowed here after move
    |              |
    |              value moved into `b` here
-   |              move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |              move occurs because `b` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -120,7 +120,7 @@
    |                                 ^   ----- value borrowed here after move
    |                                 |
    |                                 value moved into `d` here
-   |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |                                 move occurs because `d` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -135,7 +135,7 @@
    |         |    |
    |         |    value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `[U; 2]`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -149,7 +149,7 @@
    |         ^        ----- value borrowed here after move
    |         |
    |         value moved into `a` here
-   |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `Option<U>`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -164,7 +164,7 @@
    |         |                 |
    |         |                 value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `Option<(U, U)>`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -178,7 +178,7 @@
    |                   ^^^^^   --------- value borrowed here after move
    |                   |
    |                   value moved into `b` here
-   |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |                   move occurs because `b` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -192,7 +192,7 @@
    |                                      ^   ----- value borrowed here after move
    |                                      |
    |                                      value moved into `d` here
-   |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |                                      move occurs because `d` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -207,7 +207,7 @@
    |         |             |
    |         |             value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `Option<[U; 2]>`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -221,7 +221,7 @@
    |         ^        ----- value borrowed here after move
    |         |
    |         value moved into `a` here
-   |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `Option<U>`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -236,7 +236,7 @@
    |         |                 |
    |         |                 value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `Option<(U, U)>`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -250,7 +250,7 @@
    |                   ^^^^^   --------- value borrowed here after move
    |                   |
    |                   value moved into `b` here
-   |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |                   move occurs because `b` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -264,7 +264,7 @@
    |                                      ^   ----- value borrowed here after move
    |                                      |
    |                                      value moved into `d` here
-   |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |                                      move occurs because `d` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -279,7 +279,7 @@
    |         |             |
    |         |             value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `Option<[U; 2]>`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -349,7 +349,7 @@
    |           ^   ----- value borrowed here after move
    |           |
    |           value moved into `a` here
-   |           move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |           move occurs because `a` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -364,7 +364,7 @@
    |           |            |
    |           |            value borrowed here after move
    |           value moved into `a` here
-   |           move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |           move occurs because `a` has type `(U, U)`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -378,7 +378,7 @@
    |                    ^   ----- value borrowed here after move
    |                    |
    |                    value moved into `b` here
-   |                    move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |                    move occurs because `b` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -392,7 +392,7 @@
    |                               ^^^^^   ----- value borrowed here after move
    |                               |
    |                               value moved into `d` here
-   |                               move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |                               move occurs because `d` has type `U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -417,7 +417,7 @@
    |           |    |
    |           |    value borrowed here after move
    |           value moved into `a` here
-   |           move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |           move occurs because `a` has type `[U; 2]`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index 3446148..76085f8 100644
--- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -78,7 +78,7 @@
    |         |    |
    |         |    value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `(U, U)`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -94,7 +94,7 @@
    |         |    |   value borrowed here after move
    |         |    value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -108,7 +108,7 @@
    |         ^        --------- value borrowed here after move
    |         |
    |         value moved into `a` here
-   |         move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `&mut U`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -123,7 +123,7 @@
    |         |         |
    |         |         value borrowed here after move
    |         value moved into `a` here
-   |         move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
+   |         move occurs because `a` has type `&mut (U, U)`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index 36515c1..a0a43e8 100644
--- a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -29,7 +29,7 @@
    |                             ^   ----- value borrowed here after move
    |                             |
    |                             value moved into `b` here
-   |                             move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
+   |                             move occurs because `b` has type `NotCopy`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
index 90d0fd7..68976c1 100644
--- a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr
@@ -107,17 +107,17 @@
 LL |         match $s { $($t)+ => {}, u128::MAX => todo!() }
    |                                ++++++++++++++++++++++
 
-error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `5_u128..` not covered
   --> $DIR/exhaustiveness.rs:61:8
    |
 LL |     m!(0u128, 0..=4);
-   |        ^^^^^ pattern `5_u128..=u128::MAX` not covered
+   |        ^^^^^ pattern `5_u128..` not covered
    |
    = note: the matched value is of type `u128`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL |         match $s { $($t)+ => {}, 5_u128..=u128::MAX => todo!() }
-   |                                +++++++++++++++++++++++++++++++
+LL |         match $s { $($t)+ => {}, 5_u128.. => todo!() }
+   |                                +++++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/exhaustiveness.rs:62:8
diff --git a/tests/ui/resolve/conflicting-primitive-names.rs b/tests/ui/resolve/conflicting-primitive-names.rs
new file mode 100644
index 0000000..79b6990
--- /dev/null
+++ b/tests/ui/resolve/conflicting-primitive-names.rs
@@ -0,0 +1,30 @@
+//@ check-pass
+#![allow(non_camel_case_types)]
+#![allow(unused)]
+
+// Ensure that primitives do not interfere with user types of similar names
+
+macro_rules! make_ty_mod {
+    ($modname:ident, $ty:tt) => {
+        mod $modname {
+            struct $ty {
+                a: i32,
+            }
+
+            fn assignment() {
+                let $ty = ();
+            }
+
+            fn access(a: $ty) -> i32 {
+                a.a
+            }
+        }
+    };
+}
+
+make_ty_mod!(check_f16, f16);
+make_ty_mod!(check_f32, f32);
+make_ty_mod!(check_f64, f64);
+make_ty_mod!(check_f128, f128);
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed
index 8a67b20..d95faef 100644
--- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed
+++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.fixed
@@ -18,6 +18,16 @@
     }
 }
 
+// This is used to make `use std::ops::Index;` not unused_import.
+// details in fix(#122373) for issue #121331
+pub struct C;
+impl Index<str> for C {
+    type Output = ();
+    fn index(&self, _: str) -> &Self::Output {
+        &()
+    }
+}
+
 mod inner {
     pub trait Trait<T> {}
 }
@@ -29,4 +39,5 @@
 impl Trait<u8> for () {}
 //~^ ERROR unnecessary qualification
 
+impl Trait<A> for A {}
 fn main() {}
diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs
index 528edb3..0eee8f7 100644
--- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs
+++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs
@@ -18,6 +18,16 @@
     }
 }
 
+// This is used to make `use std::ops::Index;` not unused_import.
+// details in fix(#122373) for issue #121331
+pub struct C;
+impl Index<str> for C {
+    type Output = ();
+    fn index(&self, _: str) -> &Self::Output {
+        &()
+    }
+}
+
 mod inner {
     pub trait Trait<T> {}
 }
@@ -29,4 +39,5 @@
 impl inner::Trait<u8> for () {}
 //~^ ERROR unnecessary qualification
 
+impl Trait<A> for A {}
 fn main() {}
diff --git a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr
index bcda721..e105b75 100644
--- a/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr
+++ b/tests/ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.stderr
@@ -16,7 +16,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:29:6
+  --> $DIR/issue-113808-invalid-unused-qualifications-suggestion.rs:39:6
    |
 LL | impl inner::Trait<u8> for () {}
    |      ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed.rs b/tests/ui/resolve/primitive-f16-f128-shadowed.rs
new file mode 100644
index 0000000..ed3fb44
--- /dev/null
+++ b/tests/ui/resolve/primitive-f16-f128-shadowed.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: --crate-type=lib
+//@ check-pass
+
+// Verify that gates for the `f16` and `f128` features do not apply to user types
+
+mod binary16 {
+    #[allow(non_camel_case_types)]
+    pub struct f16(u16);
+}
+
+mod binary128 {
+    #[allow(non_camel_case_types)]
+    pub struct f128(u128);
+}
+
+pub use binary128::f128;
+pub use binary16::f16;
+
+mod private16 {
+    use crate::f16;
+
+    pub trait SealedHalf {}
+    impl SealedHalf for f16 {}
+}
+
+mod private128 {
+    use crate::f128;
+
+    pub trait SealedQuad {}
+    impl SealedQuad for f128 {}
+}
diff --git a/tests/ui/resolve/primitive-usage.rs b/tests/ui/resolve/primitive-usage.rs
new file mode 100644
index 0000000..b00d18a
--- /dev/null
+++ b/tests/ui/resolve/primitive-usage.rs
@@ -0,0 +1,42 @@
+//@ run-pass
+#![allow(unused)]
+#![feature(f128)]
+#![feature(f16)]
+
+// Same as the feature gate tests but ensure we can use the types
+mod check_f128 {
+    const A: f128 = 10.0;
+
+    pub fn foo() {
+        let a: f128 = 100.0;
+        let b = 0.0f128;
+        bar(1.23);
+    }
+
+    fn bar(a: f128) {}
+
+    struct Bar {
+        a: f128,
+    }
+}
+
+mod check_f16 {
+    const A: f16 = 10.0;
+
+    pub fn foo() {
+        let a: f16 = 100.0;
+        let b = 0.0f16;
+        bar(1.23);
+    }
+
+    fn bar(a: f16) {}
+
+    struct Bar {
+        a: f16,
+    }
+}
+
+fn main() {
+    check_f128::foo();
+    check_f16::foo();
+}
diff --git a/tests/ui/resolve/unused-qualifications-suggestion.fixed b/tests/ui/resolve/unused-qualifications-suggestion.fixed
index 6935f61..22e0dae 100644
--- a/tests/ui/resolve/unused-qualifications-suggestion.fixed
+++ b/tests/ui/resolve/unused-qualifications-suggestion.fixed
@@ -16,8 +16,10 @@
     use foo::bar;
     bar();
     //~^ ERROR unnecessary qualification
+    bar();
 
     use baz::qux::quux;
     quux();
     //~^ ERROR unnecessary qualification
+    quux();
 }
diff --git a/tests/ui/resolve/unused-qualifications-suggestion.rs b/tests/ui/resolve/unused-qualifications-suggestion.rs
index b3fe04f..89516c1 100644
--- a/tests/ui/resolve/unused-qualifications-suggestion.rs
+++ b/tests/ui/resolve/unused-qualifications-suggestion.rs
@@ -16,8 +16,10 @@
     use foo::bar;
     foo::bar();
     //~^ ERROR unnecessary qualification
+    bar();
 
     use baz::qux::quux;
     baz::qux::quux();
     //~^ ERROR unnecessary qualification
+    quux();
 }
diff --git a/tests/ui/resolve/unused-qualifications-suggestion.stderr b/tests/ui/resolve/unused-qualifications-suggestion.stderr
index e3dac37..5b71ba9 100644
--- a/tests/ui/resolve/unused-qualifications-suggestion.stderr
+++ b/tests/ui/resolve/unused-qualifications-suggestion.stderr
@@ -16,7 +16,7 @@
    |
 
 error: unnecessary qualification
-  --> $DIR/unused-qualifications-suggestion.rs:21:5
+  --> $DIR/unused-qualifications-suggestion.rs:22:5
    |
 LL |     baz::qux::quux();
    |     ^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs
index c0e13a5..5d11941 100644
--- a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs
+++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.rs
@@ -26,8 +26,8 @@
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
-    //~^ ERROR mismatched types
-    //~| ERROR mismatched types
+    //~^ ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
     //~| ERROR implementation of `FnOnce` is not general enough
     //~| ERROR implementation of `FnOnce` is not general enough
 };
diff --git a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr
index 52c700c..5c98a9d 100644
--- a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr
+++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr
@@ -1,21 +1,20 @@
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/rfc1623-2.rs:28:8
    |
 LL |     f: &id,
-   |        ^^^ one type is more general than the other
+   |        ^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)`
-              found trait `Fn(&Foo<'_>)`
+   = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `Fn<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
 
-error[E0308]: mismatched types
+error: implementation of `Fn` is not general enough
   --> $DIR/rfc1623-2.rs:28:8
    |
 LL |     f: &id,
-   |        ^^^ one type is more general than the other
+   |        ^^^ implementation of `Fn` is not general enough
    |
-   = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)`
-              found trait `Fn(&Foo<'_>)`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `Fn<(&'a Foo<'1>,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&Foo<'2>,)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/rfc1623-2.rs:28:8
@@ -37,4 +36,3 @@
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/simd/const-err-trumps-simd-err.rs b/tests/ui/simd/const-err-trumps-simd-err.rs
new file mode 100644
index 0000000..06a7472
--- /dev/null
+++ b/tests/ui/simd/const-err-trumps-simd-err.rs
@@ -0,0 +1,24 @@
+//@build-fail
+//! Make sure that monomorphization-time const errors from `static_assert` take priority over the
+//! error from simd_extract. Basically this checks that if a const fails to evaluate in some
+//! function, we don't bother codegen'ing the function.
+#![feature(generic_arg_infer)]
+#![feature(core_intrinsics)]
+#![feature(repr_simd)]
+#![feature(inline_const)]
+use std::intrinsics::simd::*;
+
+#[repr(simd)]
+#[allow(non_camel_case_types)]
+struct int8x4_t(u8,u8,u8,u8);
+
+fn get_elem<const LANE: u32>(a: int8x4_t) -> u8 {
+    const { assert!(LANE < 4); } // the error should be here...
+    //~^ ERROR failed
+    //~| assertion failed
+    unsafe { simd_extract(a, LANE) } // ...not here
+}
+
+fn main() {
+    get_elem::<4>(int8x4_t(0,0,0,0));
+}
diff --git a/tests/ui/simd/const-err-trumps-simd-err.stderr b/tests/ui/simd/const-err-trumps-simd-err.stderr
new file mode 100644
index 0000000..1e46667
--- /dev/null
+++ b/tests/ui/simd/const-err-trumps-simd-err.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `get_elem::<4>::{constant#0}` failed
+  --> $DIR/const-err-trumps-simd-err.rs:16:13
+   |
+LL |     const { assert!(LANE < 4); } // the error should be here...
+   |             ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: LANE < 4', $DIR/const-err-trumps-simd-err.rs:16:13
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/const-err-trumps-simd-err.rs:16:5
+   |
+LL |     const { assert!(LANE < 4); } // the error should be here...
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn get_elem::<4>`
+  --> $DIR/const-err-trumps-simd-err.rs:23:5
+   |
+LL |     get_elem::<4>(int8x4_t(0,0,0,0));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr
index 579a5d5..dc24833 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/hir-stats.stderr
@@ -17,7 +17,7 @@
 ast-stats-1 FnDecl                   120 ( 1.8%)             5            24
 ast-stats-1 FieldDef                 160 ( 2.4%)             2            80
 ast-stats-1 Stmt                     160 ( 2.4%)             5            32
-ast-stats-1 - Local                     32 ( 0.5%)             1
+ast-stats-1 - Let                       32 ( 0.5%)             1
 ast-stats-1 - MacCall                   32 ( 0.5%)             1
 ast-stats-1 - Expr                      96 ( 1.4%)             3
 ast-stats-1 Param                    160 ( 2.4%)             4            40
@@ -75,7 +75,7 @@
 ast-stats-2 - Normal                    96 ( 1.3%)             3
 ast-stats-2 FieldDef                 160 ( 2.2%)             2            80
 ast-stats-2 Stmt                     160 ( 2.2%)             5            32
-ast-stats-2 - Local                     32 ( 0.4%)             1
+ast-stats-2 - Let                       32 ( 0.4%)             1
 ast-stats-2 - Semi                      32 ( 0.4%)             1
 ast-stats-2 - Expr                      96 ( 1.3%)             3
 ast-stats-2 Param                    160 ( 2.2%)             4            40
@@ -131,7 +131,7 @@
 hir-stats Arm                       80 ( 0.9%)             2            40
 hir-stats FieldDef                  96 ( 1.1%)             2            48
 hir-stats Stmt                      96 ( 1.1%)             3            32
-hir-stats - Local                     32 ( 0.4%)             1
+hir-stats - Let                       32 ( 0.4%)             1
 hir-stats - Semi                      32 ( 0.4%)             1
 hir-stats - Expr                      32 ( 0.4%)             1
 hir-stats FnDecl                   120 ( 1.3%)             3            40
diff --git a/tests/ui/suggestions/clone-bounds-121524.rs b/tests/ui/suggestions/clone-bounds-121524.rs
new file mode 100644
index 0000000..8cd60b4
--- /dev/null
+++ b/tests/ui/suggestions/clone-bounds-121524.rs
@@ -0,0 +1,19 @@
+#[derive(Clone)]
+struct ThingThatDoesAThing;
+
+trait DoesAThing {}
+
+impl DoesAThing for ThingThatDoesAThing {}
+
+fn clones_impl_ref_inline(thing: &impl DoesAThing) {
+    //~^ HELP consider further restricting this bound
+    drops_impl_owned(thing.clone()); //~ ERROR E0277
+    //~^ NOTE copies the reference
+    //~| NOTE the trait `DoesAThing` is not implemented for `&impl DoesAThing`
+}
+
+fn drops_impl_owned(_thing: impl DoesAThing) { }
+
+fn main() {
+    clones_impl_ref_inline(&ThingThatDoesAThing);
+}
diff --git a/tests/ui/suggestions/clone-bounds-121524.stderr b/tests/ui/suggestions/clone-bounds-121524.stderr
new file mode 100644
index 0000000..6d60508
--- /dev/null
+++ b/tests/ui/suggestions/clone-bounds-121524.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `&impl DoesAThing: DoesAThing` is not satisfied
+  --> $DIR/clone-bounds-121524.rs:10:22
+   |
+LL |     drops_impl_owned(thing.clone());
+   |                      ^^^^^^^^^^^^^ the trait `DoesAThing` is not implemented for `&impl DoesAThing`
+   |
+note: this `clone()` copies the reference, which does not do anything, because `impl DoesAThing` does not implement `Clone`
+  --> $DIR/clone-bounds-121524.rs:10:28
+   |
+LL |     drops_impl_owned(thing.clone());
+   |                            ^^^^^
+help: consider further restricting this bound
+   |
+LL | fn clones_impl_ref_inline(thing: &impl DoesAThing + Clone) {
+   |                                                   +++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
index ee92452..f0acf1d 100644
--- a/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
+++ b/tests/ui/suggestions/late-bound-in-borrow-closure-sugg.stderr
@@ -10,7 +10,7 @@
    |            required by a bound introduced by this call
    |
    = note: expected closure signature `for<'a, 'b> fn(&'a mut Trader<'b>) -> _`
-              found closure signature `for<'a> fn(Trader<'a>) -> _`
+              found closure signature `fn(Trader<'_>) -> _`
 note: required by a bound in `Trader::<'a>::set_closure`
   --> $DIR/late-bound-in-borrow-closure-sugg.rs:15:50
    |
diff --git a/tests/ui/suggestions/ref-pattern-binding.stderr b/tests/ui/suggestions/ref-pattern-binding.stderr
index 69ce5d4..af21c6a 100644
--- a/tests/ui/suggestions/ref-pattern-binding.stderr
+++ b/tests/ui/suggestions/ref-pattern-binding.stderr
@@ -5,7 +5,7 @@
    |         ^^^^^^   --------- value borrowed here after move
    |         |
    |         value moved into `_moved` here
-   |         move occurs because `_moved` has type `String` which does not implement the `Copy` trait
+   |         move occurs because `_moved` has type `String`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
@@ -35,7 +35,7 @@
    |         ^^^^^^       ----- value borrowed here after move
    |         |
    |         value moved into `_moved` here
-   |         move occurs because `_moved` has type `S` which does not implement the `Copy` trait
+   |         move occurs because `_moved` has type `S`, which does not implement the `Copy` trait
    |
 help: borrow this binding in the pattern to avoid moving the value
    |
diff --git a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr
index 6c25962..40e16dd 100644
--- a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr
+++ b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr
@@ -8,6 +8,27 @@
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0309]: the placeholder type `!1_"F"` may not live long enough
+  --> $DIR/type-match-with-late-bound.rs:8:1
+   |
+LL |   async fn walk2<'a, T: 'a>(_: T)
+   |   ^              -- the placeholder type `!1_"F"` must be valid for the lifetime `'a` as defined here...
+   |  _|
+   | |
+LL | | where
+LL | |     for<F> F: 'a,
+   | |_________________^ ...so that the type `F` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/type-match-with-late-bound.rs:10:15
+   |
+LL |     for<F> F: 'a,
+   |               ^^
+help: consider adding an explicit lifetime bound
+   |
+LL |     for<F> F: 'a, !1_"F": 'a
+   |                 ~~~~~~~~~~~~
+
+error[E0309]: the placeholder type `!1_"F"` may not live long enough
   --> $DIR/type-match-with-late-bound.rs:11:1
    |
 LL | async fn walk2<'a, T: 'a>(_: T)
@@ -35,6 +56,6 @@
 LL |     for<F> F: 'a, !2_"F": 'a
    |                 ~~~~~~~~~~~~
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr
new file mode 100644
index 0000000..098ab71
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.current.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-upcasting-ok.rs:17:5
+   |
+LL |     x
+   |     ^ one type is more general than the other
+   |
+   = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+              found existential trait ref `for<'a> Supertrait<'a, 'a>`
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-upcasting-ok.rs:17:5
+   |
+LL |     x
+   |     ^ one type is more general than the other
+   |
+   = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+              found existential trait ref `for<'a> Supertrait<'a, 'a>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr
new file mode 100644
index 0000000..ac516fd
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.next.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-upcasting-ok.rs:17:5
+   |
+LL | fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
+   |                                                ------------------------------- expected `&dyn for<'a> Supertrait<'a, 'a>` because of return type
+LL |     x
+   |     ^ expected trait `Supertrait`, found trait `Subtrait`
+   |
+   = note: expected reference `&dyn for<'a> Supertrait<'a, 'a>`
+              found reference `&dyn for<'a, 'b> Subtrait<'a, 'b>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
new file mode 100644
index 0000000..0074320
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ok.rs
@@ -0,0 +1,19 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// We should be able to instantiate a binder during trait upcasting.
+// This test could be `check-pass`, but we should make sure that we
+// do so in both trait solvers.
+#![feature(trait_upcasting)]
+#![crate_type = "rlib"]
+trait Supertrait<'a, 'b> {}
+
+trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
+
+impl<'a> Supertrait<'a, 'a> for () {}
+impl<'a> Subtrait<'a, 'a> for () {}
+fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
+    x //~ ERROR mismatched types
+    //[current]~^ ERROR mismatched types
+}
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr
new file mode 100644
index 0000000..bac8298
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-upcasting-ub.rs:22:5
+   |
+LL |     x
+   |     ^ one type is more general than the other
+   |
+   = note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
+              found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-upcasting-ub.rs:22:5
+   |
+LL |     x
+   |     ^ one type is more general than the other
+   |
+   = note: expected existential trait ref `for<'a> Supertrait<'a, 'a>`
+              found existential trait ref `for<'a, 'b> Supertrait<'a, 'b>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr
new file mode 100644
index 0000000..b82f1eef
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/higher-ranked-upcasting-ub.rs:22:5
+   |
+LL | fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
+   |                                                 ----------------------------------- expected `&dyn for<'a, 'b> Supertrait<'a, 'b>` because of return type
+LL |     x
+   |     ^ expected trait `Supertrait`, found trait `Subtrait`
+   |
+   = note: expected reference `&dyn for<'a, 'b> Supertrait<'a, 'b>`
+              found reference `&dyn for<'a> Subtrait<'a, 'a>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
new file mode 100644
index 0000000..2cf6fc7
--- /dev/null
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
@@ -0,0 +1,37 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// We previously wrongly instantiated binders during trait upcasting,
+// allowing the super trait to be more generic than the sub trait.
+// This was unsound.
+#![feature(trait_upcasting)]
+trait Supertrait<'a, 'b> {
+    fn cast(&self, x: &'a str) -> &'b str;
+}
+
+trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
+
+impl<'a> Supertrait<'a, 'a> for () {
+    fn cast(&self, x: &'a str) -> &'a str {
+        x
+    }
+}
+impl<'a> Subtrait<'a, 'a> for () {}
+fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
+    x //~ ERROR mismatched types
+    //[current]~^ ERROR mismatched types
+}
+
+fn transmute<'a, 'b>(x: &'a str) -> &'b str {
+    unsound(&()).cast(x)
+}
+
+fn main() {
+    let x;
+    {
+        let mut temp = String::from("hello there");
+        x = transmute(temp.as_str());
+    }
+    println!("{x}");
+}
diff --git a/tests/ui/transmutability/alignment/align-fail.stderr b/tests/ui/transmutability/alignment/align-fail.stderr
index c92c3d8..f05e55f 100644
--- a/tests/ui/transmutability/alignment/align-fail.stderr
+++ b/tests/ui/transmutability/alignment/align-fail.stderr
@@ -2,7 +2,7 @@
   --> $DIR/align-fail.rs:21:55
    |
 LL | ...tatic [u8; 0], &'static [u16; 0]>();
-   |                   ^^^^^^^^^^^^^^^^^ The minimum alignment of `&[u8; 0]` (1) should be greater than that of `&[u16; 0]` (2)
+   |                   ^^^^^^^^^^^^^^^^^ the minimum alignment of `&[u8; 0]` (1) should be greater than that of `&[u16; 0]` (2)
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/align-fail.rs:9:14
diff --git a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr
index fd21ac3..e486928 100644
--- a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr
+++ b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_require_well_defined_layout.rs:25:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `[String; 0]` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `[String; 0]` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -23,7 +23,7 @@
   --> $DIR/should_require_well_defined_layout.rs:26:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `[String; 0]` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -44,7 +44,7 @@
   --> $DIR/should_require_well_defined_layout.rs:31:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `[String; 1]` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `[String; 1]` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -65,7 +65,7 @@
   --> $DIR/should_require_well_defined_layout.rs:32:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `[String; 1]` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -86,7 +86,7 @@
   --> $DIR/should_require_well_defined_layout.rs:37:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `[String; 2]` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `[String; 2]` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -107,7 +107,7 @@
   --> $DIR/should_require_well_defined_layout.rs:38:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `[String; 2]` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
diff --git a/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr
index b2ff04e..6c88bf4 100644
--- a/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr
+++ b/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr
@@ -2,7 +2,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:46:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `Zst` is smaller than the size of `V0i8`
+   |                                            ^^^^^^^ the size of `Zst` is smaller than the size of `V0i8`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -24,7 +24,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:48:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0i8` is smaller than the size of `u16`
+   |                                            ^^^^^^ the size of `V0i8` is smaller than the size of `u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -46,7 +46,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:54:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `Zst` is smaller than the size of `V0u8`
+   |                                            ^^^^^^^ the size of `Zst` is smaller than the size of `V0u8`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -68,7 +68,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:56:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0u8` is smaller than the size of `u16`
+   |                                            ^^^^^^ the size of `V0u8` is smaller than the size of `u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -90,7 +90,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:68:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u8` is smaller than the size of `V0i16`
+   |                                            ^^^^^^^ the size of `u8` is smaller than the size of `V0i16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -112,7 +112,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:70:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0i16` is smaller than the size of `u32`
+   |                                            ^^^^^^ the size of `V0i16` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -134,7 +134,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:76:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u8` is smaller than the size of `V0u16`
+   |                                            ^^^^^^^ the size of `u8` is smaller than the size of `V0u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -156,7 +156,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:78:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0u16` is smaller than the size of `u32`
+   |                                            ^^^^^^ the size of `V0u16` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -178,7 +178,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:90:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u16` is smaller than the size of `V0i32`
+   |                                            ^^^^^^^ the size of `u16` is smaller than the size of `V0i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -200,7 +200,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:92:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0i32` is smaller than the size of `u64`
+   |                                            ^^^^^^ the size of `V0i32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -222,7 +222,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:98:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u16` is smaller than the size of `V0u32`
+   |                                            ^^^^^^^ the size of `u16` is smaller than the size of `V0u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -244,7 +244,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:100:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0u32` is smaller than the size of `u64`
+   |                                            ^^^^^^ the size of `V0u32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -266,7 +266,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:112:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u32` is smaller than the size of `V0i64`
+   |                                            ^^^^^^^ the size of `u32` is smaller than the size of `V0i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -288,7 +288,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:114:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0i64` is smaller than the size of `u128`
+   |                                            ^^^^^^ the size of `V0i64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -310,7 +310,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:120:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u32` is smaller than the size of `V0u64`
+   |                                            ^^^^^^^ the size of `u32` is smaller than the size of `V0u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -332,7 +332,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:122:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0u64` is smaller than the size of `u128`
+   |                                            ^^^^^^ the size of `V0u64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -354,7 +354,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:134:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u8` is smaller than the size of `V0isize`
+   |                                            ^^^^^^^ the size of `u8` is smaller than the size of `V0isize`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -376,7 +376,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:136:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0isize` is smaller than the size of `[usize; 2]`
+   |                                            ^^^^^^ the size of `V0isize` is smaller than the size of `[usize; 2]`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -398,7 +398,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:142:44
    |
 LL |         assert::is_transmutable::<Smaller, Current>();
-   |                                            ^^^^^^^ The size of `u8` is smaller than the size of `V0usize`
+   |                                            ^^^^^^^ the size of `u8` is smaller than the size of `V0usize`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@@ -420,7 +420,7 @@
   --> $DIR/primitive_reprs_should_have_correct_length.rs:144:44
    |
 LL |         assert::is_transmutable::<Current, Larger>();
-   |                                            ^^^^^^ The size of `V0usize` is smaller than the size of `[usize; 2]`
+   |                                            ^^^^^^ the size of `V0usize` is smaller than the size of `[usize; 2]`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
index 2473093..2a683de 100644
--- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
+++ b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_require_well_defined_layout.rs:27:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `void::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `void::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:13:14
@@ -24,7 +24,7 @@
   --> $DIR/should_require_well_defined_layout.rs:28:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `void::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `void::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:13:14
@@ -46,7 +46,7 @@
   --> $DIR/should_require_well_defined_layout.rs:33:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `singleton::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:13:14
@@ -68,7 +68,7 @@
   --> $DIR/should_require_well_defined_layout.rs:34:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `singleton::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:13:14
@@ -90,7 +90,7 @@
   --> $DIR/should_require_well_defined_layout.rs:39:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `duplex::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:13:14
@@ -112,7 +112,7 @@
   --> $DIR/should_require_well_defined_layout.rs:40:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `duplex::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:13:14
diff --git a/tests/ui/transmutability/enums/should_pad_variants.stderr b/tests/ui/transmutability/enums/should_pad_variants.stderr
index 13b4c80..da4294b 100644
--- a/tests/ui/transmutability/enums/should_pad_variants.stderr
+++ b/tests/ui/transmutability/enums/should_pad_variants.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_pad_variants.rs:43:36
    |
 LL |     assert::is_transmutable::<Src, Dst>();
-   |                                    ^^^ The size of `Src` is smaller than the size of `Dst`
+   |                                    ^^^ the size of `Src` is smaller than the size of `Dst`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/should_pad_variants.rs:13:14
diff --git a/tests/ui/transmutability/enums/should_respect_endianness.stderr b/tests/ui/transmutability/enums/should_respect_endianness.stderr
index c2a2eb5..9f88bb0 100644
--- a/tests/ui/transmutability/enums/should_respect_endianness.stderr
+++ b/tests/ui/transmutability/enums/should_respect_endianness.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_respect_endianness.rs:35:36
    |
 LL |     assert::is_transmutable::<Src, Unexpected>();
-   |                                    ^^^^^^^^^^ At least one value of `Src` isn't a bit-valid value of `Unexpected`
+   |                                    ^^^^^^^^^^ at least one value of `Src` isn't a bit-valid value of `Unexpected`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/should_respect_endianness.rs:13:14
diff --git a/tests/ui/transmutability/primitives/bool-mut.stderr b/tests/ui/transmutability/primitives/bool-mut.stderr
index c4f295f..464c275 100644
--- a/tests/ui/transmutability/primitives/bool-mut.stderr
+++ b/tests/ui/transmutability/primitives/bool-mut.stderr
@@ -2,7 +2,7 @@
   --> $DIR/bool-mut.rs:15:50
    |
 LL |     assert::is_transmutable::<&'static mut bool, &'static mut u8>()
-   |                                                  ^^^^^^^^^^^^^^^ At least one value of `u8` isn't a bit-valid value of `bool`
+   |                                                  ^^^^^^^^^^^^^^^ at least one value of `u8` isn't a bit-valid value of `bool`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/bool-mut.rs:10:14
diff --git a/tests/ui/transmutability/primitives/bool.current.stderr b/tests/ui/transmutability/primitives/bool.current.stderr
index 98e4a10..da6a4a4 100644
--- a/tests/ui/transmutability/primitives/bool.current.stderr
+++ b/tests/ui/transmutability/primitives/bool.current.stderr
@@ -2,7 +2,7 @@
   --> $DIR/bool.rs:21:35
    |
 LL |     assert::is_transmutable::<u8, bool>();
-   |                                   ^^^^ At least one value of `u8` isn't a bit-valid value of `bool`
+   |                                   ^^^^ at least one value of `u8` isn't a bit-valid value of `bool`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/bool.rs:11:14
diff --git a/tests/ui/transmutability/primitives/bool.next.stderr b/tests/ui/transmutability/primitives/bool.next.stderr
index 98e4a10..da6a4a4 100644
--- a/tests/ui/transmutability/primitives/bool.next.stderr
+++ b/tests/ui/transmutability/primitives/bool.next.stderr
@@ -2,7 +2,7 @@
   --> $DIR/bool.rs:21:35
    |
 LL |     assert::is_transmutable::<u8, bool>();
-   |                                   ^^^^ At least one value of `u8` isn't a bit-valid value of `bool`
+   |                                   ^^^^ at least one value of `u8` isn't a bit-valid value of `bool`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/bool.rs:11:14
diff --git a/tests/ui/transmutability/primitives/numbers.current.stderr b/tests/ui/transmutability/primitives/numbers.current.stderr
index 7a80e44..0a9b9d1 100644
--- a/tests/ui/transmutability/primitives/numbers.current.stderr
+++ b/tests/ui/transmutability/primitives/numbers.current.stderr
@@ -2,7 +2,7 @@
   --> $DIR/numbers.rs:64:40
    |
 LL |     assert::is_transmutable::<   i8,   i16>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `i16`
+   |                                        ^^^ the size of `i8` is smaller than the size of `i16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -17,7 +17,7 @@
   --> $DIR/numbers.rs:65:40
    |
 LL |     assert::is_transmutable::<   i8,   u16>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `u16`
+   |                                        ^^^ the size of `i8` is smaller than the size of `u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -32,7 +32,7 @@
   --> $DIR/numbers.rs:66:40
    |
 LL |     assert::is_transmutable::<   i8,   i32>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `i32`
+   |                                        ^^^ the size of `i8` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -47,7 +47,7 @@
   --> $DIR/numbers.rs:67:40
    |
 LL |     assert::is_transmutable::<   i8,   f32>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `f32`
+   |                                        ^^^ the size of `i8` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -62,7 +62,7 @@
   --> $DIR/numbers.rs:68:40
    |
 LL |     assert::is_transmutable::<   i8,   u32>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `u32`
+   |                                        ^^^ the size of `i8` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -77,7 +77,7 @@
   --> $DIR/numbers.rs:69:40
    |
 LL |     assert::is_transmutable::<   i8,   u64>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `u64`
+   |                                        ^^^ the size of `i8` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -92,7 +92,7 @@
   --> $DIR/numbers.rs:70:40
    |
 LL |     assert::is_transmutable::<   i8,   i64>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `i64`
+   |                                        ^^^ the size of `i8` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -107,7 +107,7 @@
   --> $DIR/numbers.rs:71:40
    |
 LL |     assert::is_transmutable::<   i8,   f64>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `f64`
+   |                                        ^^^ the size of `i8` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -122,7 +122,7 @@
   --> $DIR/numbers.rs:72:39
    |
 LL |     assert::is_transmutable::<   i8,  u128>();
-   |                                       ^^^^ The size of `i8` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i8` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -137,7 +137,7 @@
   --> $DIR/numbers.rs:73:39
    |
 LL |     assert::is_transmutable::<   i8,  i128>();
-   |                                       ^^^^ The size of `i8` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i8` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -152,7 +152,7 @@
   --> $DIR/numbers.rs:75:40
    |
 LL |     assert::is_transmutable::<   u8,   i16>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `i16`
+   |                                        ^^^ the size of `u8` is smaller than the size of `i16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -167,7 +167,7 @@
   --> $DIR/numbers.rs:76:40
    |
 LL |     assert::is_transmutable::<   u8,   u16>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `u16`
+   |                                        ^^^ the size of `u8` is smaller than the size of `u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -182,7 +182,7 @@
   --> $DIR/numbers.rs:77:40
    |
 LL |     assert::is_transmutable::<   u8,   i32>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `i32`
+   |                                        ^^^ the size of `u8` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -197,7 +197,7 @@
   --> $DIR/numbers.rs:78:40
    |
 LL |     assert::is_transmutable::<   u8,   f32>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `f32`
+   |                                        ^^^ the size of `u8` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -212,7 +212,7 @@
   --> $DIR/numbers.rs:79:40
    |
 LL |     assert::is_transmutable::<   u8,   u32>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `u32`
+   |                                        ^^^ the size of `u8` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -227,7 +227,7 @@
   --> $DIR/numbers.rs:80:40
    |
 LL |     assert::is_transmutable::<   u8,   u64>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `u64`
+   |                                        ^^^ the size of `u8` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -242,7 +242,7 @@
   --> $DIR/numbers.rs:81:40
    |
 LL |     assert::is_transmutable::<   u8,   i64>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `i64`
+   |                                        ^^^ the size of `u8` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -257,7 +257,7 @@
   --> $DIR/numbers.rs:82:40
    |
 LL |     assert::is_transmutable::<   u8,   f64>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `f64`
+   |                                        ^^^ the size of `u8` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -272,7 +272,7 @@
   --> $DIR/numbers.rs:83:39
    |
 LL |     assert::is_transmutable::<   u8,  u128>();
-   |                                       ^^^^ The size of `u8` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u8` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -287,7 +287,7 @@
   --> $DIR/numbers.rs:84:39
    |
 LL |     assert::is_transmutable::<   u8,  i128>();
-   |                                       ^^^^ The size of `u8` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u8` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -302,7 +302,7 @@
   --> $DIR/numbers.rs:86:40
    |
 LL |     assert::is_transmutable::<  i16,   i32>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `i32`
+   |                                        ^^^ the size of `i16` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -317,7 +317,7 @@
   --> $DIR/numbers.rs:87:40
    |
 LL |     assert::is_transmutable::<  i16,   f32>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `f32`
+   |                                        ^^^ the size of `i16` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -332,7 +332,7 @@
   --> $DIR/numbers.rs:88:40
    |
 LL |     assert::is_transmutable::<  i16,   u32>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `u32`
+   |                                        ^^^ the size of `i16` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -347,7 +347,7 @@
   --> $DIR/numbers.rs:89:40
    |
 LL |     assert::is_transmutable::<  i16,   u64>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `u64`
+   |                                        ^^^ the size of `i16` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -362,7 +362,7 @@
   --> $DIR/numbers.rs:90:40
    |
 LL |     assert::is_transmutable::<  i16,   i64>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `i64`
+   |                                        ^^^ the size of `i16` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -377,7 +377,7 @@
   --> $DIR/numbers.rs:91:40
    |
 LL |     assert::is_transmutable::<  i16,   f64>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `f64`
+   |                                        ^^^ the size of `i16` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -392,7 +392,7 @@
   --> $DIR/numbers.rs:92:39
    |
 LL |     assert::is_transmutable::<  i16,  u128>();
-   |                                       ^^^^ The size of `i16` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i16` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -407,7 +407,7 @@
   --> $DIR/numbers.rs:93:39
    |
 LL |     assert::is_transmutable::<  i16,  i128>();
-   |                                       ^^^^ The size of `i16` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i16` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -422,7 +422,7 @@
   --> $DIR/numbers.rs:95:40
    |
 LL |     assert::is_transmutable::<  u16,   i32>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `i32`
+   |                                        ^^^ the size of `u16` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -437,7 +437,7 @@
   --> $DIR/numbers.rs:96:40
    |
 LL |     assert::is_transmutable::<  u16,   f32>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `f32`
+   |                                        ^^^ the size of `u16` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -452,7 +452,7 @@
   --> $DIR/numbers.rs:97:40
    |
 LL |     assert::is_transmutable::<  u16,   u32>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `u32`
+   |                                        ^^^ the size of `u16` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -467,7 +467,7 @@
   --> $DIR/numbers.rs:98:40
    |
 LL |     assert::is_transmutable::<  u16,   u64>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `u64`
+   |                                        ^^^ the size of `u16` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -482,7 +482,7 @@
   --> $DIR/numbers.rs:99:40
    |
 LL |     assert::is_transmutable::<  u16,   i64>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `i64`
+   |                                        ^^^ the size of `u16` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -497,7 +497,7 @@
   --> $DIR/numbers.rs:100:40
    |
 LL |     assert::is_transmutable::<  u16,   f64>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `f64`
+   |                                        ^^^ the size of `u16` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -512,7 +512,7 @@
   --> $DIR/numbers.rs:101:39
    |
 LL |     assert::is_transmutable::<  u16,  u128>();
-   |                                       ^^^^ The size of `u16` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u16` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -527,7 +527,7 @@
   --> $DIR/numbers.rs:102:39
    |
 LL |     assert::is_transmutable::<  u16,  i128>();
-   |                                       ^^^^ The size of `u16` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u16` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -542,7 +542,7 @@
   --> $DIR/numbers.rs:104:40
    |
 LL |     assert::is_transmutable::<  i32,   u64>();
-   |                                        ^^^ The size of `i32` is smaller than the size of `u64`
+   |                                        ^^^ the size of `i32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -557,7 +557,7 @@
   --> $DIR/numbers.rs:105:40
    |
 LL |     assert::is_transmutable::<  i32,   i64>();
-   |                                        ^^^ The size of `i32` is smaller than the size of `i64`
+   |                                        ^^^ the size of `i32` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -572,7 +572,7 @@
   --> $DIR/numbers.rs:106:40
    |
 LL |     assert::is_transmutable::<  i32,   f64>();
-   |                                        ^^^ The size of `i32` is smaller than the size of `f64`
+   |                                        ^^^ the size of `i32` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -587,7 +587,7 @@
   --> $DIR/numbers.rs:107:39
    |
 LL |     assert::is_transmutable::<  i32,  u128>();
-   |                                       ^^^^ The size of `i32` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i32` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -602,7 +602,7 @@
   --> $DIR/numbers.rs:108:39
    |
 LL |     assert::is_transmutable::<  i32,  i128>();
-   |                                       ^^^^ The size of `i32` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i32` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -617,7 +617,7 @@
   --> $DIR/numbers.rs:110:40
    |
 LL |     assert::is_transmutable::<  f32,   u64>();
-   |                                        ^^^ The size of `f32` is smaller than the size of `u64`
+   |                                        ^^^ the size of `f32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -632,7 +632,7 @@
   --> $DIR/numbers.rs:111:40
    |
 LL |     assert::is_transmutable::<  f32,   i64>();
-   |                                        ^^^ The size of `f32` is smaller than the size of `i64`
+   |                                        ^^^ the size of `f32` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -647,7 +647,7 @@
   --> $DIR/numbers.rs:112:40
    |
 LL |     assert::is_transmutable::<  f32,   f64>();
-   |                                        ^^^ The size of `f32` is smaller than the size of `f64`
+   |                                        ^^^ the size of `f32` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -662,7 +662,7 @@
   --> $DIR/numbers.rs:113:39
    |
 LL |     assert::is_transmutable::<  f32,  u128>();
-   |                                       ^^^^ The size of `f32` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `f32` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -677,7 +677,7 @@
   --> $DIR/numbers.rs:114:39
    |
 LL |     assert::is_transmutable::<  f32,  i128>();
-   |                                       ^^^^ The size of `f32` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `f32` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -692,7 +692,7 @@
   --> $DIR/numbers.rs:116:40
    |
 LL |     assert::is_transmutable::<  u32,   u64>();
-   |                                        ^^^ The size of `u32` is smaller than the size of `u64`
+   |                                        ^^^ the size of `u32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -707,7 +707,7 @@
   --> $DIR/numbers.rs:117:40
    |
 LL |     assert::is_transmutable::<  u32,   i64>();
-   |                                        ^^^ The size of `u32` is smaller than the size of `i64`
+   |                                        ^^^ the size of `u32` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -722,7 +722,7 @@
   --> $DIR/numbers.rs:118:40
    |
 LL |     assert::is_transmutable::<  u32,   f64>();
-   |                                        ^^^ The size of `u32` is smaller than the size of `f64`
+   |                                        ^^^ the size of `u32` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -737,7 +737,7 @@
   --> $DIR/numbers.rs:119:39
    |
 LL |     assert::is_transmutable::<  u32,  u128>();
-   |                                       ^^^^ The size of `u32` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u32` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -752,7 +752,7 @@
   --> $DIR/numbers.rs:120:39
    |
 LL |     assert::is_transmutable::<  u32,  i128>();
-   |                                       ^^^^ The size of `u32` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u32` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -767,7 +767,7 @@
   --> $DIR/numbers.rs:122:39
    |
 LL |     assert::is_transmutable::<  u64,  u128>();
-   |                                       ^^^^ The size of `u64` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -782,7 +782,7 @@
   --> $DIR/numbers.rs:123:39
    |
 LL |     assert::is_transmutable::<  u64,  i128>();
-   |                                       ^^^^ The size of `u64` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u64` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -797,7 +797,7 @@
   --> $DIR/numbers.rs:125:39
    |
 LL |     assert::is_transmutable::<  i64,  u128>();
-   |                                       ^^^^ The size of `i64` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -812,7 +812,7 @@
   --> $DIR/numbers.rs:126:39
    |
 LL |     assert::is_transmutable::<  i64,  i128>();
-   |                                       ^^^^ The size of `i64` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i64` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -827,7 +827,7 @@
   --> $DIR/numbers.rs:128:39
    |
 LL |     assert::is_transmutable::<  f64,  u128>();
-   |                                       ^^^^ The size of `f64` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `f64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -842,7 +842,7 @@
   --> $DIR/numbers.rs:129:39
    |
 LL |     assert::is_transmutable::<  f64,  i128>();
-   |                                       ^^^^ The size of `f64` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `f64` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
diff --git a/tests/ui/transmutability/primitives/numbers.next.stderr b/tests/ui/transmutability/primitives/numbers.next.stderr
index 7a80e44..0a9b9d1 100644
--- a/tests/ui/transmutability/primitives/numbers.next.stderr
+++ b/tests/ui/transmutability/primitives/numbers.next.stderr
@@ -2,7 +2,7 @@
   --> $DIR/numbers.rs:64:40
    |
 LL |     assert::is_transmutable::<   i8,   i16>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `i16`
+   |                                        ^^^ the size of `i8` is smaller than the size of `i16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -17,7 +17,7 @@
   --> $DIR/numbers.rs:65:40
    |
 LL |     assert::is_transmutable::<   i8,   u16>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `u16`
+   |                                        ^^^ the size of `i8` is smaller than the size of `u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -32,7 +32,7 @@
   --> $DIR/numbers.rs:66:40
    |
 LL |     assert::is_transmutable::<   i8,   i32>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `i32`
+   |                                        ^^^ the size of `i8` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -47,7 +47,7 @@
   --> $DIR/numbers.rs:67:40
    |
 LL |     assert::is_transmutable::<   i8,   f32>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `f32`
+   |                                        ^^^ the size of `i8` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -62,7 +62,7 @@
   --> $DIR/numbers.rs:68:40
    |
 LL |     assert::is_transmutable::<   i8,   u32>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `u32`
+   |                                        ^^^ the size of `i8` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -77,7 +77,7 @@
   --> $DIR/numbers.rs:69:40
    |
 LL |     assert::is_transmutable::<   i8,   u64>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `u64`
+   |                                        ^^^ the size of `i8` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -92,7 +92,7 @@
   --> $DIR/numbers.rs:70:40
    |
 LL |     assert::is_transmutable::<   i8,   i64>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `i64`
+   |                                        ^^^ the size of `i8` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -107,7 +107,7 @@
   --> $DIR/numbers.rs:71:40
    |
 LL |     assert::is_transmutable::<   i8,   f64>();
-   |                                        ^^^ The size of `i8` is smaller than the size of `f64`
+   |                                        ^^^ the size of `i8` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -122,7 +122,7 @@
   --> $DIR/numbers.rs:72:39
    |
 LL |     assert::is_transmutable::<   i8,  u128>();
-   |                                       ^^^^ The size of `i8` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i8` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -137,7 +137,7 @@
   --> $DIR/numbers.rs:73:39
    |
 LL |     assert::is_transmutable::<   i8,  i128>();
-   |                                       ^^^^ The size of `i8` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i8` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -152,7 +152,7 @@
   --> $DIR/numbers.rs:75:40
    |
 LL |     assert::is_transmutable::<   u8,   i16>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `i16`
+   |                                        ^^^ the size of `u8` is smaller than the size of `i16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -167,7 +167,7 @@
   --> $DIR/numbers.rs:76:40
    |
 LL |     assert::is_transmutable::<   u8,   u16>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `u16`
+   |                                        ^^^ the size of `u8` is smaller than the size of `u16`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -182,7 +182,7 @@
   --> $DIR/numbers.rs:77:40
    |
 LL |     assert::is_transmutable::<   u8,   i32>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `i32`
+   |                                        ^^^ the size of `u8` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -197,7 +197,7 @@
   --> $DIR/numbers.rs:78:40
    |
 LL |     assert::is_transmutable::<   u8,   f32>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `f32`
+   |                                        ^^^ the size of `u8` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -212,7 +212,7 @@
   --> $DIR/numbers.rs:79:40
    |
 LL |     assert::is_transmutable::<   u8,   u32>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `u32`
+   |                                        ^^^ the size of `u8` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -227,7 +227,7 @@
   --> $DIR/numbers.rs:80:40
    |
 LL |     assert::is_transmutable::<   u8,   u64>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `u64`
+   |                                        ^^^ the size of `u8` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -242,7 +242,7 @@
   --> $DIR/numbers.rs:81:40
    |
 LL |     assert::is_transmutable::<   u8,   i64>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `i64`
+   |                                        ^^^ the size of `u8` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -257,7 +257,7 @@
   --> $DIR/numbers.rs:82:40
    |
 LL |     assert::is_transmutable::<   u8,   f64>();
-   |                                        ^^^ The size of `u8` is smaller than the size of `f64`
+   |                                        ^^^ the size of `u8` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -272,7 +272,7 @@
   --> $DIR/numbers.rs:83:39
    |
 LL |     assert::is_transmutable::<   u8,  u128>();
-   |                                       ^^^^ The size of `u8` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u8` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -287,7 +287,7 @@
   --> $DIR/numbers.rs:84:39
    |
 LL |     assert::is_transmutable::<   u8,  i128>();
-   |                                       ^^^^ The size of `u8` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u8` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -302,7 +302,7 @@
   --> $DIR/numbers.rs:86:40
    |
 LL |     assert::is_transmutable::<  i16,   i32>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `i32`
+   |                                        ^^^ the size of `i16` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -317,7 +317,7 @@
   --> $DIR/numbers.rs:87:40
    |
 LL |     assert::is_transmutable::<  i16,   f32>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `f32`
+   |                                        ^^^ the size of `i16` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -332,7 +332,7 @@
   --> $DIR/numbers.rs:88:40
    |
 LL |     assert::is_transmutable::<  i16,   u32>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `u32`
+   |                                        ^^^ the size of `i16` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -347,7 +347,7 @@
   --> $DIR/numbers.rs:89:40
    |
 LL |     assert::is_transmutable::<  i16,   u64>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `u64`
+   |                                        ^^^ the size of `i16` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -362,7 +362,7 @@
   --> $DIR/numbers.rs:90:40
    |
 LL |     assert::is_transmutable::<  i16,   i64>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `i64`
+   |                                        ^^^ the size of `i16` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -377,7 +377,7 @@
   --> $DIR/numbers.rs:91:40
    |
 LL |     assert::is_transmutable::<  i16,   f64>();
-   |                                        ^^^ The size of `i16` is smaller than the size of `f64`
+   |                                        ^^^ the size of `i16` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -392,7 +392,7 @@
   --> $DIR/numbers.rs:92:39
    |
 LL |     assert::is_transmutable::<  i16,  u128>();
-   |                                       ^^^^ The size of `i16` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i16` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -407,7 +407,7 @@
   --> $DIR/numbers.rs:93:39
    |
 LL |     assert::is_transmutable::<  i16,  i128>();
-   |                                       ^^^^ The size of `i16` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i16` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -422,7 +422,7 @@
   --> $DIR/numbers.rs:95:40
    |
 LL |     assert::is_transmutable::<  u16,   i32>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `i32`
+   |                                        ^^^ the size of `u16` is smaller than the size of `i32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -437,7 +437,7 @@
   --> $DIR/numbers.rs:96:40
    |
 LL |     assert::is_transmutable::<  u16,   f32>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `f32`
+   |                                        ^^^ the size of `u16` is smaller than the size of `f32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -452,7 +452,7 @@
   --> $DIR/numbers.rs:97:40
    |
 LL |     assert::is_transmutable::<  u16,   u32>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `u32`
+   |                                        ^^^ the size of `u16` is smaller than the size of `u32`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -467,7 +467,7 @@
   --> $DIR/numbers.rs:98:40
    |
 LL |     assert::is_transmutable::<  u16,   u64>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `u64`
+   |                                        ^^^ the size of `u16` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -482,7 +482,7 @@
   --> $DIR/numbers.rs:99:40
    |
 LL |     assert::is_transmutable::<  u16,   i64>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `i64`
+   |                                        ^^^ the size of `u16` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -497,7 +497,7 @@
   --> $DIR/numbers.rs:100:40
    |
 LL |     assert::is_transmutable::<  u16,   f64>();
-   |                                        ^^^ The size of `u16` is smaller than the size of `f64`
+   |                                        ^^^ the size of `u16` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -512,7 +512,7 @@
   --> $DIR/numbers.rs:101:39
    |
 LL |     assert::is_transmutable::<  u16,  u128>();
-   |                                       ^^^^ The size of `u16` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u16` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -527,7 +527,7 @@
   --> $DIR/numbers.rs:102:39
    |
 LL |     assert::is_transmutable::<  u16,  i128>();
-   |                                       ^^^^ The size of `u16` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u16` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -542,7 +542,7 @@
   --> $DIR/numbers.rs:104:40
    |
 LL |     assert::is_transmutable::<  i32,   u64>();
-   |                                        ^^^ The size of `i32` is smaller than the size of `u64`
+   |                                        ^^^ the size of `i32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -557,7 +557,7 @@
   --> $DIR/numbers.rs:105:40
    |
 LL |     assert::is_transmutable::<  i32,   i64>();
-   |                                        ^^^ The size of `i32` is smaller than the size of `i64`
+   |                                        ^^^ the size of `i32` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -572,7 +572,7 @@
   --> $DIR/numbers.rs:106:40
    |
 LL |     assert::is_transmutable::<  i32,   f64>();
-   |                                        ^^^ The size of `i32` is smaller than the size of `f64`
+   |                                        ^^^ the size of `i32` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -587,7 +587,7 @@
   --> $DIR/numbers.rs:107:39
    |
 LL |     assert::is_transmutable::<  i32,  u128>();
-   |                                       ^^^^ The size of `i32` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i32` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -602,7 +602,7 @@
   --> $DIR/numbers.rs:108:39
    |
 LL |     assert::is_transmutable::<  i32,  i128>();
-   |                                       ^^^^ The size of `i32` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i32` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -617,7 +617,7 @@
   --> $DIR/numbers.rs:110:40
    |
 LL |     assert::is_transmutable::<  f32,   u64>();
-   |                                        ^^^ The size of `f32` is smaller than the size of `u64`
+   |                                        ^^^ the size of `f32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -632,7 +632,7 @@
   --> $DIR/numbers.rs:111:40
    |
 LL |     assert::is_transmutable::<  f32,   i64>();
-   |                                        ^^^ The size of `f32` is smaller than the size of `i64`
+   |                                        ^^^ the size of `f32` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -647,7 +647,7 @@
   --> $DIR/numbers.rs:112:40
    |
 LL |     assert::is_transmutable::<  f32,   f64>();
-   |                                        ^^^ The size of `f32` is smaller than the size of `f64`
+   |                                        ^^^ the size of `f32` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -662,7 +662,7 @@
   --> $DIR/numbers.rs:113:39
    |
 LL |     assert::is_transmutable::<  f32,  u128>();
-   |                                       ^^^^ The size of `f32` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `f32` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -677,7 +677,7 @@
   --> $DIR/numbers.rs:114:39
    |
 LL |     assert::is_transmutable::<  f32,  i128>();
-   |                                       ^^^^ The size of `f32` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `f32` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -692,7 +692,7 @@
   --> $DIR/numbers.rs:116:40
    |
 LL |     assert::is_transmutable::<  u32,   u64>();
-   |                                        ^^^ The size of `u32` is smaller than the size of `u64`
+   |                                        ^^^ the size of `u32` is smaller than the size of `u64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -707,7 +707,7 @@
   --> $DIR/numbers.rs:117:40
    |
 LL |     assert::is_transmutable::<  u32,   i64>();
-   |                                        ^^^ The size of `u32` is smaller than the size of `i64`
+   |                                        ^^^ the size of `u32` is smaller than the size of `i64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -722,7 +722,7 @@
   --> $DIR/numbers.rs:118:40
    |
 LL |     assert::is_transmutable::<  u32,   f64>();
-   |                                        ^^^ The size of `u32` is smaller than the size of `f64`
+   |                                        ^^^ the size of `u32` is smaller than the size of `f64`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -737,7 +737,7 @@
   --> $DIR/numbers.rs:119:39
    |
 LL |     assert::is_transmutable::<  u32,  u128>();
-   |                                       ^^^^ The size of `u32` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u32` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -752,7 +752,7 @@
   --> $DIR/numbers.rs:120:39
    |
 LL |     assert::is_transmutable::<  u32,  i128>();
-   |                                       ^^^^ The size of `u32` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u32` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -767,7 +767,7 @@
   --> $DIR/numbers.rs:122:39
    |
 LL |     assert::is_transmutable::<  u64,  u128>();
-   |                                       ^^^^ The size of `u64` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `u64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -782,7 +782,7 @@
   --> $DIR/numbers.rs:123:39
    |
 LL |     assert::is_transmutable::<  u64,  i128>();
-   |                                       ^^^^ The size of `u64` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `u64` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -797,7 +797,7 @@
   --> $DIR/numbers.rs:125:39
    |
 LL |     assert::is_transmutable::<  i64,  u128>();
-   |                                       ^^^^ The size of `i64` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `i64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -812,7 +812,7 @@
   --> $DIR/numbers.rs:126:39
    |
 LL |     assert::is_transmutable::<  i64,  i128>();
-   |                                       ^^^^ The size of `i64` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `i64` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -827,7 +827,7 @@
   --> $DIR/numbers.rs:128:39
    |
 LL |     assert::is_transmutable::<  f64,  u128>();
-   |                                       ^^^^ The size of `f64` is smaller than the size of `u128`
+   |                                       ^^^^ the size of `f64` is smaller than the size of `u128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
@@ -842,7 +842,7 @@
   --> $DIR/numbers.rs:129:39
    |
 LL |     assert::is_transmutable::<  f64,  i128>();
-   |                                       ^^^^ The size of `f64` is smaller than the size of `i128`
+   |                                       ^^^^ the size of `f64` is smaller than the size of `i128`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/numbers.rs:14:14
diff --git a/tests/ui/transmutability/primitives/unit.current.stderr b/tests/ui/transmutability/primitives/unit.current.stderr
index b2831db..52b708d 100644
--- a/tests/ui/transmutability/primitives/unit.current.stderr
+++ b/tests/ui/transmutability/primitives/unit.current.stderr
@@ -2,7 +2,7 @@
   --> $DIR/unit.rs:31:35
    |
 LL |     assert::is_transmutable::<(), u8>();
-   |                                   ^^ The size of `()` is smaller than the size of `u8`
+   |                                   ^^ the size of `()` is smaller than the size of `u8`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/unit.rs:16:14
diff --git a/tests/ui/transmutability/primitives/unit.next.stderr b/tests/ui/transmutability/primitives/unit.next.stderr
index b2831db..52b708d 100644
--- a/tests/ui/transmutability/primitives/unit.next.stderr
+++ b/tests/ui/transmutability/primitives/unit.next.stderr
@@ -2,7 +2,7 @@
   --> $DIR/unit.rs:31:35
    |
 LL |     assert::is_transmutable::<(), u8>();
-   |                                   ^^ The size of `()` is smaller than the size of `u8`
+   |                                   ^^ the size of `()` is smaller than the size of `u8`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/unit.rs:16:14
diff --git a/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr b/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr
index 305fca3..2b7cab1 100644
--- a/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr
+++ b/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr
@@ -2,7 +2,7 @@
   --> $DIR/recursive-wrapper-types-bit-incompatible.rs:23:49
    |
 LL |     assert::is_maybe_transmutable::<&'static B, &'static A>();
-   |                                                 ^^^^^^^^^^ At least one value of `B` isn't a bit-valid value of `A`
+   |                                                 ^^^^^^^^^^ at least one value of `B` isn't a bit-valid value of `A`
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/recursive-wrapper-types-bit-incompatible.rs:9:14
diff --git a/tests/ui/transmutability/references/reject_extension.rs b/tests/ui/transmutability/references/reject_extension.rs
new file mode 100644
index 0000000..161da57
--- /dev/null
+++ b/tests/ui/transmutability/references/reject_extension.rs
@@ -0,0 +1,49 @@
+//@ check-fail
+
+//! Reject extensions behind references.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<
+            Src,
+            {
+                Assume {
+                    alignment: true,
+                    lifetimes: true,
+                    safety: true,
+                    validity: true,
+                }
+            },
+        >,
+    {
+    }
+}
+
+#[repr(C, packed)]
+struct Packed<T>(T);
+
+fn reject_extension() {
+    #[repr(C, align(2))]
+    struct Two(u8);
+
+    #[repr(C, align(4))]
+    struct Four(u8);
+
+    // These two types differ in the number of trailing padding bytes they have.
+    type Src = Packed<Two>;
+    type Dst = Packed<Four>;
+
+    const _: () = {
+        use std::mem::size_of;
+        assert!(size_of::<Src>() == 2);
+        assert!(size_of::<Dst>() == 4);
+    };
+
+    assert::is_transmutable::<&Src, &Dst>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/tests/ui/transmutability/references/reject_extension.stderr b/tests/ui/transmutability/references/reject_extension.stderr
new file mode 100644
index 0000000..88dd031
--- /dev/null
+++ b/tests/ui/transmutability/references/reject_extension.stderr
@@ -0,0 +1,25 @@
+error[E0277]: `&Packed<Two>` cannot be safely transmuted into `&Packed<Four>`
+  --> $DIR/reject_extension.rs:48:37
+   |
+LL |     assert::is_transmutable::<&Src, &Dst>();
+   |                                     ^^^^ the referent size of `&Packed<Two>` (2 bytes) is smaller than that of `&Packed<Four>` (4 bytes)
+   |
+note: required by a bound in `is_transmutable`
+  --> $DIR/reject_extension.rs:13:14
+   |
+LL |       pub fn is_transmutable<Src, Dst>()
+   |              --------------- required by a bound in this function
+LL |       where
+LL |           Dst: BikeshedIntrinsicFrom<
+   |  ______________^
+LL | |             Src,
+LL | |             {
+LL | |                 Assume {
+...  |
+LL | |             },
+LL | |         >,
+   | |_________^ required by this bound in `is_transmutable`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/transmutability/references/unit-to-u8.stderr b/tests/ui/transmutability/references/unit-to-u8.stderr
index e2eb504..5d73dfd 100644
--- a/tests/ui/transmutability/references/unit-to-u8.stderr
+++ b/tests/ui/transmutability/references/unit-to-u8.stderr
@@ -1,8 +1,8 @@
-error[E0277]: `Unit` cannot be safely transmuted into `u8`
+error[E0277]: `&Unit` cannot be safely transmuted into `&u8`
   --> $DIR/unit-to-u8.rs:22:52
    |
 LL |     assert::is_maybe_transmutable::<&'static Unit, &'static u8>();
-   |                                                    ^^^^^^^^^^^ The size of `Unit` is smaller than the size of `u8`
+   |                                                    ^^^^^^^^^^^ the referent size of `&Unit` (0 bytes) is smaller than that of `&u8` (1 bytes)
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/unit-to-u8.rs:9:14
diff --git a/tests/ui/transmutability/region-infer.stderr b/tests/ui/transmutability/region-infer.stderr
index 5497af2..03c4682 100644
--- a/tests/ui/transmutability/region-infer.stderr
+++ b/tests/ui/transmutability/region-infer.stderr
@@ -2,7 +2,7 @@
   --> $DIR/region-infer.rs:18:5
    |
 LL |     test();
-   |     ^^^^^^ The size of `()` is smaller than the size of `W<'_>`
+   |     ^^^^^^ the size of `()` is smaller than the size of `W<'_>`
    |
 note: required by a bound in `test`
   --> $DIR/region-infer.rs:10:12
diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
index 924422d..77788f7 100644
--- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
+++ b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_require_well_defined_layout.rs:27:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `should_reject_repr_rust::unit::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -24,7 +24,7 @@
   --> $DIR/should_require_well_defined_layout.rs:28:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `should_reject_repr_rust::unit::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -46,7 +46,7 @@
   --> $DIR/should_require_well_defined_layout.rs:33:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `should_reject_repr_rust::tuple::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -68,7 +68,7 @@
   --> $DIR/should_require_well_defined_layout.rs:34:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `should_reject_repr_rust::tuple::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -90,7 +90,7 @@
   --> $DIR/should_require_well_defined_layout.rs:39:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `should_reject_repr_rust::braces::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -112,7 +112,7 @@
   --> $DIR/should_require_well_defined_layout.rs:40:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `should_reject_repr_rust::braces::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -134,7 +134,7 @@
   --> $DIR/should_require_well_defined_layout.rs:45:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `aligned::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -156,7 +156,7 @@
   --> $DIR/should_require_well_defined_layout.rs:46:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `aligned::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -178,7 +178,7 @@
   --> $DIR/should_require_well_defined_layout.rs:51:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ `packed::repr_rust` does not have a well-specified layout
+   |                                                    ^^ analyzing the transmutability of `packed::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -200,7 +200,7 @@
   --> $DIR/should_require_well_defined_layout.rs:52:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ `packed::repr_rust` does not have a well-specified layout
+   |                                               ^^^^^^^^^ analyzing the transmutability of `packed::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -222,7 +222,7 @@
   --> $DIR/should_require_well_defined_layout.rs:58:49
    |
 LL |         assert::is_maybe_transmutable::<repr_c, ()>();
-   |                                                 ^^ `nested::repr_c` does not have a well-specified layout
+   |                                                 ^^ analyzing the transmutability of `nested::repr_c` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -244,7 +244,7 @@
   --> $DIR/should_require_well_defined_layout.rs:59:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_c>();
-   |                                               ^^^^^^ `nested::repr_c` does not have a well-specified layout
+   |                                               ^^^^^^ analyzing the transmutability of `nested::repr_c` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
diff --git a/tests/ui/transmutability/transmute-padding-ice.stderr b/tests/ui/transmutability/transmute-padding-ice.stderr
index c48a5cd..4c121d4 100644
--- a/tests/ui/transmutability/transmute-padding-ice.stderr
+++ b/tests/ui/transmutability/transmute-padding-ice.stderr
@@ -2,7 +2,7 @@
   --> $DIR/transmute-padding-ice.rs:25:40
    |
 LL |     assert::is_maybe_transmutable::<B, A>();
-   |                                        ^ The size of `B` is smaller than the size of `A`
+   |                                        ^ the size of `B` is smaller than the size of `A`
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/transmute-padding-ice.rs:10:14
diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
index ee0e8a6..bec07f1 100644
--- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
+++ b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_require_well_defined_layout.rs:29:48
    |
 LL |     assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                ^^ `should_reject_repr_rust::repr_rust` does not have a well-specified layout
+   |                                                ^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -24,7 +24,7 @@
   --> $DIR/should_require_well_defined_layout.rs:30:43
    |
 LL |     assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                           ^^^^^^^^^ `should_reject_repr_rust::repr_rust` does not have a well-specified layout
+   |                                           ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported.
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
diff --git a/tests/ui/transmutability/unions/should_pad_variants.stderr b/tests/ui/transmutability/unions/should_pad_variants.stderr
index 13b4c80..da4294b 100644
--- a/tests/ui/transmutability/unions/should_pad_variants.stderr
+++ b/tests/ui/transmutability/unions/should_pad_variants.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_pad_variants.rs:43:36
    |
 LL |     assert::is_transmutable::<Src, Dst>();
-   |                                    ^^^ The size of `Src` is smaller than the size of `Dst`
+   |                                    ^^^ the size of `Src` is smaller than the size of `Dst`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/should_pad_variants.rs:13:14
diff --git a/tests/ui/transmutability/unions/should_reject_contraction.stderr b/tests/ui/transmutability/unions/should_reject_contraction.stderr
index a3e387a..20eaa3a 100644
--- a/tests/ui/transmutability/unions/should_reject_contraction.stderr
+++ b/tests/ui/transmutability/unions/should_reject_contraction.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_reject_contraction.rs:34:41
    |
 LL |     assert::is_transmutable::<Superset, Subset>();
-   |                                         ^^^^^^ At least one value of `Superset` isn't a bit-valid value of `Subset`
+   |                                         ^^^^^^ at least one value of `Superset` isn't a bit-valid value of `Subset`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/should_reject_contraction.rs:12:14
diff --git a/tests/ui/transmutability/unions/should_reject_disjoint.stderr b/tests/ui/transmutability/unions/should_reject_disjoint.stderr
index 447ab6d..ea47797 100644
--- a/tests/ui/transmutability/unions/should_reject_disjoint.stderr
+++ b/tests/ui/transmutability/unions/should_reject_disjoint.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_reject_disjoint.rs:32:40
    |
 LL |     assert::is_maybe_transmutable::<A, B>();
-   |                                        ^ At least one value of `A` isn't a bit-valid value of `B`
+   |                                        ^ at least one value of `A` isn't a bit-valid value of `B`
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_reject_disjoint.rs:12:14
@@ -17,7 +17,7 @@
   --> $DIR/should_reject_disjoint.rs:33:40
    |
 LL |     assert::is_maybe_transmutable::<B, A>();
-   |                                        ^ At least one value of `B` isn't a bit-valid value of `A`
+   |                                        ^ at least one value of `B` isn't a bit-valid value of `A`
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_reject_disjoint.rs:12:14
diff --git a/tests/ui/transmutability/unions/should_reject_intersecting.stderr b/tests/ui/transmutability/unions/should_reject_intersecting.stderr
index f0763bc..79dec65 100644
--- a/tests/ui/transmutability/unions/should_reject_intersecting.stderr
+++ b/tests/ui/transmutability/unions/should_reject_intersecting.stderr
@@ -2,7 +2,7 @@
   --> $DIR/should_reject_intersecting.rs:35:34
    |
 LL |     assert::is_transmutable::<A, B>();
-   |                                  ^ At least one value of `A` isn't a bit-valid value of `B`
+   |                                  ^ at least one value of `A` isn't a bit-valid value of `B`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/should_reject_intersecting.rs:13:14
@@ -17,7 +17,7 @@
   --> $DIR/should_reject_intersecting.rs:36:34
    |
 LL |     assert::is_transmutable::<B, A>();
-   |                                  ^ At least one value of `B` isn't a bit-valid value of `A`
+   |                                  ^ at least one value of `B` isn't a bit-valid value of `A`
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/should_reject_intersecting.rs:13:14
diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs
index 0ad6e7a..7c0de39 100644
--- a/tests/ui/type-alias-impl-trait/in-where-clause.rs
+++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs
@@ -1,5 +1,5 @@
 //! We evaluate `1 + 2` with `Reveal::All` during typeck, causing
-//! us to to get the concrete type of `Bar` while computing it.
+//! us to get the concrete type of `Bar` while computing it.
 //! This again requires type checking `foo`.
 #![feature(type_alias_impl_trait)]
 type Bar = impl Sized;
diff --git a/tests/ui/typeck/ice-self-mismatch-const-generics.rs b/tests/ui/typeck/ice-self-mismatch-const-generics.rs
new file mode 100644
index 0000000..43f435b
--- /dev/null
+++ b/tests/ui/typeck/ice-self-mismatch-const-generics.rs
@@ -0,0 +1,25 @@
+// Checks that the following does not ICE when constructing type mismatch diagnostic involving
+// `Self` and const generics.
+// Issue: <https://github.com/rust-lang/rust/issues/122467>
+
+pub struct GenericStruct<const N: usize, T> {
+    thing: T,
+}
+
+impl<T> GenericStruct<0, T> {
+    pub fn new(thing: T) -> GenericStruct<1, T> {
+        Self { thing }
+        //~^ ERROR mismatched types
+    }
+}
+
+pub struct GenericStruct2<const M: usize, T>(T);
+
+impl<T> GenericStruct2<0, T> {
+    pub fn new(thing: T) -> GenericStruct2<1, T> {
+        Self { 0: thing }
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/ice-self-mismatch-const-generics.stderr b/tests/ui/typeck/ice-self-mismatch-const-generics.stderr
new file mode 100644
index 0000000..c502ea4
--- /dev/null
+++ b/tests/ui/typeck/ice-self-mismatch-const-generics.stderr
@@ -0,0 +1,37 @@
+error[E0308]: mismatched types
+  --> $DIR/ice-self-mismatch-const-generics.rs:11:9
+   |
+LL | impl<T> GenericStruct<0, T> {
+   |         ------------------- this is the type of the `Self` literal
+LL |     pub fn new(thing: T) -> GenericStruct<1, T> {
+   |                             ------------------- expected `GenericStruct<1, T>` because of return type
+LL |         Self { thing }
+   |         ^^^^^^^^^^^^^^ expected `1`, found `0`
+   |
+   = note: expected struct `GenericStruct<_, 1>`
+              found struct `GenericStruct<_, 0>`
+help: use the type name directly
+   |
+LL |         GenericStruct::<1, T> { thing }
+   |         ~~~~~~~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/ice-self-mismatch-const-generics.rs:20:9
+   |
+LL | impl<T> GenericStruct2<0, T> {
+   |         -------------------- this is the type of the `Self` literal
+LL |     pub fn new(thing: T) -> GenericStruct2<1, T> {
+   |                             -------------------- expected `GenericStruct2<1, T>` because of return type
+LL |         Self { 0: thing }
+   |         ^^^^^^^^^^^^^^^^^ expected `1`, found `0`
+   |
+   = note: expected struct `GenericStruct2<_, 1>`
+              found struct `GenericStruct2<_, 0>`
+help: use the type name directly
+   |
+LL |         GenericStruct2::<1, T> { 0: thing }
+   |         ~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/mismatched-map-under-self.stderr b/tests/ui/typeck/mismatched-map-under-self.stderr
index 13678b4..322bf34 100644
--- a/tests/ui/typeck/mismatched-map-under-self.stderr
+++ b/tests/ui/typeck/mismatched-map-under-self.stderr
@@ -27,7 +27,7 @@
    |              required by a bound introduced by this call
    |
    = note: expected function signature `fn(T) -> _`
-              found function signature `for<'a> fn(&'a _) -> _`
+              found function signature `fn(&_) -> _`
 note: required by a bound in `Option::<T>::map`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: consider wrapping the function in a closure
diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop-move-semantics.stderr
index b6de797..187dd66 100644
--- a/tests/ui/unop-move-semantics.stderr
+++ b/tests/ui/unop-move-semantics.stderr
@@ -9,7 +9,7 @@
 LL |     x.clone();
    |     ^ value borrowed here after move
    |
-note: calling this operator moves the left-hand side
+note: calling this operator moves the value
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 help: consider cloning the value if the performance cost is acceptable
    |
@@ -57,7 +57,7 @@
    |     |move occurs because `*m` has type `T`, which does not implement the `Copy` trait
    |     `*m` moved due to usage in operator
    |
-note: calling this operator moves the left-hand side
+note: calling this operator moves the value
   --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 
 error[E0507]: cannot move out of `*n` which is behind a shared reference
diff --git a/triagebot.toml b/triagebot.toml
index a2150a4..c972dce 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -377,6 +377,25 @@
     "compiler/rustc_middle/src/traits/solve"
 ]
 
+[autolabel."PG-exploit-mitigations"]
+trigger_files = [
+    "compiler/rustc_symbol_mangling/src/typeid",
+    "src/doc/rustc/src/exploit-mitigations.md",
+    "src/doc/unstable-book/src/compiler-flags/branch-protection.md",
+    "src/doc/unstable-book/src/compiler-flags/cf-protection.md",
+    "src/doc/unstable-book/src/compiler-flags/control-flow-guard.md",
+    "src/doc/unstable-book/src/compiler-flags/sanitizer.md",
+    "src/doc/unstable-book/src/language-features/cfg-sanitize.md",
+    "src/doc/unstable-book/src/language-features/cfi-encoding.md",
+    "src/doc/unstable-book/src/language-features/no-sanitize.md",
+    "tests/codegen/sanitizer",
+    "tests/codegen/split-lto-unit.rs",
+    "tests/codegen/stack-probes-inline.rs",
+    "tests/codegen/stack-protector.rs",
+    "tests/ui/sanitizer",
+    "tests/ui/stack-protector"
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"
@@ -642,6 +661,51 @@
 message = "Changes to the size of AST and/or HIR nodes."
 cc = ["@nnethercote"]
 
+[mentions."compiler/rustc_symbol_mangling/src/typeid"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/rustc/src/exploit-mitigations.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/compiler-flags/branch-protection.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/compiler-flags/cf-protection.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/compiler-flags/control-flow-guard.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/compiler-flags/sanitizer.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/language-features/cfg-sanitize.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/language-features/cfi-encoding.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."src/doc/unstable-book/src/language-features/no-sanitize.md"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."tests/codegen/sanitizer"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."tests/codegen/split-lto-unit.rs"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."tests/codegen/stack-probes-inline.rs"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."tests/codegen/stack-protector.rs"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."tests/ui/sanitizer"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
+[mentions."tests/ui/stack-protector"]
+cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
@@ -783,6 +847,11 @@
     "@ouz-a",
 ]
 
+project-exploit-mitigations = [
+    "@cuviper",
+    "@rcvalle",
+]
+
 [assign.owners]
 "/.github/workflows" =                                   ["infra-ci"]
 "/Cargo.lock" =                                          ["@Mark-Simulacrum"]