about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/Cargo.toml8
-rw-r--r--compiler/rustc_ast/src/ast.rs3
-rw-r--r--compiler/rustc_ast/src/format.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs16
-rw-r--r--compiler/rustc_ast/src/visit.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs55
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs9
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs5
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs11
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs13
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs52
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/parser.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs54
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs20
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs44
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs210
-rw-r--r--compiler/rustc_borrowck/src/type_check/opaque_types.rs1
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml4
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl3
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/define_opaque.rs54
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-72793.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs13
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs68
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs115
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl28
-rw-r--r--compiler/rustc_codegen_ssa/src/assert_module_sources.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs129
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs104
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs9
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs4
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs1
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs3
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0792.md4
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs21
-rw-r--r--compiler/rustc_hir/src/intravisit.rs4
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl9
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs80
-rw-r--r--compiler/rustc_hir_analysis/src/delegation.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs127
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs27
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs52
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs14
-rw-r--r--compiler/rustc_incremental/Cargo.toml2
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs4
-rw-r--r--compiler/rustc_index/src/slice.rs41
-rw-r--r--compiler/rustc_index/src/vec.rs4
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs2
-rw-r--r--compiler/rustc_interface/src/util.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_lint/src/context.rs16
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs2
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/late.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs9
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs1
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_macros/src/print_attribute.rs27
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs9
-rw-r--r--compiler/rustc_middle/src/hir/map.rs310
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs5
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs9
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs3
-rw-r--r--compiler/rustc_middle/src/query/erase.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs8
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs12
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs4
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_constant.rs7
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/builder/scope.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/util.rs22
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs46
-rw-r--r--compiler/rustc_parse_format/src/lib.rs18
-rw-r--r--compiler/rustc_passes/src/check_attr.rs19
-rw-r--r--compiler/rustc_passes/src/dead.rs6
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs2
-rw-r--r--compiler/rustc_passes/src/entry.rs6
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs7
-rw-r--r--compiler/rustc_passes/src/liveness.rs2
-rw-r--r--compiler/rustc_passes/src/loops.rs2
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs6
-rw-r--r--compiler/rustc_privacy/src/lib.rs12
-rw-r--r--compiler/rustc_resolve/messages.ftl12
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs32
-rw-r--r--compiler/rustc_resolve/src/errors.rs18
-rw-r--r--compiler/rustc_resolve/src/ident.rs61
-rw-r--r--compiler/rustc_resolve/src/late.rs109
-rw-r--r--compiler/rustc_resolve/src/lib.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs24
-rw-r--r--compiler/rustc_target/src/spec/base/linux_wasm.rs159
-rw-r--r--compiler/rustc_target/src/spec/base/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs29
-rw-r--r--compiler/rustc_target/src/target_features.rs12
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs29
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs9
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs6
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs28
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs132
-rw-r--r--compiler/rustc_type_ir/Cargo.toml3
170 files changed, 1879 insertions, 1277 deletions
diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml
index 86dc84e2016..5f9afc46a1a 100644
--- a/compiler/rustc_abi/Cargo.toml
+++ b/compiler/rustc_abi/Cargo.toml
@@ -6,13 +6,13 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-rand = { version = "0.8.4", default-features = false, optional = true }
-rand_xoshiro = { version = "0.6.0", optional = true }
-rustc_data_structures = { path = "../rustc_data_structures", optional = true  }
+rand = { version = "0.9.0", default-features = false, optional = true }
+rand_xoshiro = { version = "0.7.0", optional = true }
+rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
-rustc_serialize = { path = "../rustc_serialize", optional = true  }
+rustc_serialize = { path = "../rustc_serialize", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 002435b2d03..1b831c454e6 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3466,6 +3466,7 @@ pub struct Fn {
     pub generics: Generics,
     pub sig: FnSig,
     pub contract: Option<P<FnContract>>,
+    pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
     pub body: Option<P<Block>>,
 }
 
@@ -3763,7 +3764,7 @@ mod size_asserts {
     static_assert_size!(Block, 32);
     static_assert_size!(Expr, 72);
     static_assert_size!(ExprKind, 40);
-    static_assert_size!(Fn, 168);
+    static_assert_size!(Fn, 176);
     static_assert_size!(ForeignItem, 88);
     static_assert_size!(ForeignItemKind, 16);
     static_assert_size!(GenericArg, 24);
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index b93846c1fe6..b611ddea1d9 100644
--- a/compiler/rustc_ast/src/format.rs
+++ b/compiler/rustc_ast/src/format.rs
@@ -266,7 +266,7 @@ pub enum FormatAlignment {
 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
 pub enum FormatCount {
     /// `{:5}` or `{:.5}`
-    Literal(usize),
+    Literal(u16),
     /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
     Argument(FormatArgPosition),
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index ee894db7b96..fc31912283a 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -973,7 +973,14 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
             _ctxt,
             _ident,
             _vis,
-            Fn { defaultness, generics, contract, body, sig: FnSig { header, decl, span } },
+            Fn {
+                defaultness,
+                generics,
+                contract,
+                body,
+                sig: FnSig { header, decl, span },
+                define_opaque,
+            },
         ) => {
             // Identifier and visibility are visited as a part of the item.
             visit_defaultness(vis, defaultness);
@@ -987,6 +994,11 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
                 vis.visit_block(body);
             }
             vis.visit_span(span);
+
+            for (id, path) in define_opaque.iter_mut().flatten() {
+                vis.visit_id(id);
+                vis.visit_path(path)
+            }
         }
         FnKind::Closure(binder, coroutine_kind, decl, body) => {
             vis.visit_closure_binder(binder);
@@ -1936,7 +1948,7 @@ impl DummyAstNode for Item {
                 span: Default::default(),
                 tokens: Default::default(),
             },
-            ident: Ident::empty(),
+            ident: Ident::dummy(),
             kind: ItemKind::ExternCrate(None),
             tokens: Default::default(),
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 43ffbe9b071..cfcb0e23cb5 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -892,7 +892,14 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
             _ctxt,
             _ident,
             _vis,
-            Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, contract, body },
+            Fn {
+                defaultness: _,
+                sig: FnSig { header, decl, span: _ },
+                generics,
+                contract,
+                body,
+                define_opaque,
+            },
         ) => {
             // Identifier and visibility are visited as a part of the item.
             try_visit!(visitor.visit_fn_header(header));
@@ -900,6 +907,9 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
             try_visit!(visitor.visit_fn_decl(decl));
             visit_opt!(visitor, visit_contract, contract);
             visit_opt!(visitor, visit_block, body);
+            for (id, path) in define_opaque.iter().flatten() {
+                try_visit!(visitor.visit_path(path, *id))
+            }
         }
         FnKind::Closure(binder, coroutine_kind, decl, body) => {
             try_visit!(visitor.visit_closure_binder(binder));
@@ -1203,7 +1213,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
                 FnKind::Closure(binder, coroutine_kind, fn_decl, body),
                 *span,
                 *id
-            ))
+            ));
         }
         ExprKind::Block(block, opt_label) => {
             visit_opt!(visitor, visit_label, opt_label);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index acf35b75e4d..5bb6704dde4 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2130,26 +2130,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
     }
 
-    pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
+    fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
         let lit = self.arena.alloc(hir::Lit {
             span: sp,
-            node: ast::LitKind::Int(
-                (value as u128).into(),
-                ast::LitIntType::Unsigned(ast::UintTy::Usize),
-            ),
+            node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
         });
         self.expr(sp, hir::ExprKind::Lit(lit))
     }
 
+    pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
+        self.expr_uint(sp, ast::UintTy::Usize, value as u128)
+    }
+
     pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
-        let lit = self.arena.alloc(hir::Lit {
-            span: sp,
-            node: ast::LitKind::Int(
-                u128::from(value).into(),
-                ast::LitIntType::Unsigned(ast::UintTy::U32),
-            ),
-        });
-        self.expr(sp, hir::ExprKind::Lit(lit))
+        self.expr_uint(sp, ast::UintTy::U32, value as u128)
+    }
+
+    pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> {
+        self.expr_uint(sp, ast::UintTy::U16, value as u128)
     }
 
     pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 07b94dbc2ae..faa47274f96 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -292,7 +292,7 @@ fn make_count<'hir>(
                 hir::LangItem::FormatCount,
                 sym::Is,
             ));
-            let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]);
+            let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]);
             ctx.expr_call_mut(sp, count_is, value)
         }
         Some(FormatCount::Argument(arg)) => {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index b01ca54fb6f..9adc8bdd361 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -3,10 +3,9 @@ use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir::PredicateOrigin;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
+use rustc_hir::{self as hir, HirId, PredicateOrigin};
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
@@ -209,6 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 generics,
                 body,
                 contract,
+                define_opaque,
                 ..
             }) => {
                 self.with_new_scopes(*fn_sig_span, |this| {
@@ -237,6 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         header: this.lower_fn_header(*header, hir::Safety::Safe, attrs),
                         span: this.lower_span(*fn_sig_span),
                     };
+                    this.lower_define_opaque(hir_id, &define_opaque);
                     hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
                 })
             }
@@ -779,7 +780,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 (generics, kind, expr.is_some())
             }
-            AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
+            AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => {
                 // FIXME(contracts): Deny contract here since it won't apply to
                 // any impl method or callees.
                 let names = self.lower_fn_params_to_names(&sig.decl);
@@ -791,9 +792,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     sig.header.coroutine_kind,
                     attrs,
                 );
+                if define_opaque.is_some() {
+                    self.dcx().span_err(
+                        i.span,
+                        "only trait methods with default bodies can define opaque types",
+                    );
+                }
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
-            AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), contract, .. }) => {
+            AssocItemKind::Fn(box Fn {
+                sig,
+                generics,
+                body: Some(body),
+                contract,
+                define_opaque,
+                ..
+            }) => {
                 let body_id = self.lower_maybe_coroutine_body(
                     sig.span,
                     i.span,
@@ -812,6 +826,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     sig.header.coroutine_kind,
                     attrs,
                 );
+                self.lower_define_opaque(hir_id, &define_opaque);
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
             }
             AssocItemKind::Type(box TyAlias { generics, where_clauses, bounds, ty, .. }) => {
@@ -911,7 +926,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ImplItemKind::Const(ty, body)
                 },
             ),
-            AssocItemKind::Fn(box Fn { sig, generics, body, contract, .. }) => {
+            AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => {
                 let body_id = self.lower_maybe_coroutine_body(
                     sig.span,
                     i.span,
@@ -930,6 +945,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     sig.header.coroutine_kind,
                     attrs,
                 );
+                self.lower_define_opaque(hir_id, &define_opaque);
 
                 (generics, hir::ImplItemKind::Fn(sig, body_id))
             }
@@ -1657,6 +1673,35 @@ impl<'hir> LoweringContext<'_, 'hir> {
         (lowered_generics, res)
     }
 
+    pub(super) fn lower_define_opaque(
+        &mut self,
+        hir_id: HirId,
+        define_opaque: &Option<ThinVec<(NodeId, Path)>>,
+    ) {
+        assert_eq!(self.define_opaque, None);
+        assert!(hir_id.is_owner());
+        let Some(define_opaque) = define_opaque.as_ref() else {
+            return;
+        };
+        let define_opaque = define_opaque.iter().filter_map(|(id, path)| {
+            let res = self.resolver.get_partial_res(*id).unwrap();
+            let Some(did) = res.expect_full_res().opt_def_id() else {
+                self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
+                return None;
+            };
+            let Some(did) = did.as_local() else {
+                self.dcx().span_err(
+                    path.span,
+                    "only opaque types defined in the local crate can be defined",
+                );
+                return None;
+            };
+            Some((self.lower_span(path.span), did))
+        });
+        let define_opaque = self.arena.alloc_from_iter(define_opaque);
+        self.define_opaque = Some(define_opaque);
+    }
+
     pub(super) fn lower_generic_bound_predicate(
         &mut self,
         ident: Ident,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4cecc56909e..e5569458dbd 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -35,6 +35,7 @@
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
+#![feature(exact_size_is_empty)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(rustdoc_internals)]
@@ -97,6 +98,8 @@ struct LoweringContext<'a, 'hir> {
 
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
+    /// `#[define_opaque]` attributes
+    define_opaque: Option<&'hir [(Span, LocalDefId)]>,
     /// Attributes inside the owner being lowered.
     attrs: SortedMap<hir::ItemLocalId, &'hir [hir::Attribute]>,
     /// Collect items that were created by lowering the current owner.
@@ -154,6 +157,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
             // HirId handling.
             bodies: Vec::new(),
+            define_opaque: None,
             attrs: SortedMap::default(),
             children: Vec::default(),
             contract_ensures: None,
@@ -546,6 +550,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let current_attrs = std::mem::take(&mut self.attrs);
         let current_bodies = std::mem::take(&mut self.bodies);
+        let current_define_opaque = std::mem::take(&mut self.define_opaque);
         let current_ident_and_label_to_local_id =
             std::mem::take(&mut self.ident_and_label_to_local_id);
 
@@ -579,6 +584,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         self.attrs = current_attrs;
         self.bodies = current_bodies;
+        self.define_opaque = current_define_opaque;
         self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;
 
         #[cfg(debug_assertions)]
@@ -598,6 +604,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
+        let define_opaque = std::mem::take(&mut self.define_opaque);
         let trait_map = std::mem::take(&mut self.trait_map);
 
         #[cfg(debug_assertions)]
@@ -617,7 +624,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         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 };
-        let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
+        let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
 
         self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index f9f4035cb22..232d60be4eb 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -917,7 +917,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
             }
-            ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, contract: _, body }) => {
+            ItemKind::Fn(
+                func
+                @ box Fn { defaultness, generics: _, sig, contract: _, body, define_opaque: _ },
+            ) => {
                 self.check_defaultness(item.span, *defaultness);
 
                 let is_intrinsic =
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 01fc272a458..a8eaff7346b 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -24,7 +24,6 @@ use rustc_span::edition::Edition;
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::IdentPrinter;
 use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym};
-use thin_vec::ThinVec;
 
 use crate::pp::Breaks::{Consistent, Inconsistent};
 use crate::pp::{self, Breaks};
@@ -1978,15 +1977,7 @@ impl<'a> State<'a> {
     ) {
         self.ibox(INDENT_UNIT);
         self.print_formal_generic_params(generic_params);
-        let generics = ast::Generics {
-            params: ThinVec::new(),
-            where_clause: ast::WhereClause {
-                has_where_token: false,
-                predicates: ThinVec::new(),
-                span: DUMMY_SP,
-            },
-            span: DUMMY_SP,
-        };
+        let generics = ast::Generics::default();
         let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() };
         self.print_fn(decl, header, name, &generics);
         self.end();
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index ced0cbd2fef..6236f8ecfb5 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -650,7 +650,16 @@ impl<'a> State<'a> {
         attrs: &[ast::Attribute],
         func: &ast::Fn,
     ) {
-        let ast::Fn { defaultness, generics, sig, contract, body } = func;
+        let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func;
+
+        if let Some(define_opaque) = define_opaque {
+            for (_, path) in define_opaque {
+                self.word("define opaques from ");
+                self.print_path(path, false, 0);
+                self.word(",");
+            }
+        }
+
         if body.is_some() {
             self.head("");
         }
@@ -698,7 +707,7 @@ impl<'a> State<'a> {
         }
         self.print_generic_params(&generics.params);
         self.print_fn_params_and_ret(decl, false);
-        self.print_where_clause(&generics.where_clause)
+        self.print_where_clause(&generics.where_clause);
     }
 
     pub(crate) fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index be00d1c10e0..bbd3308809c 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -34,13 +34,17 @@ pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStabl
 /// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
 /// representation much.
 pub trait PrintAttribute {
-    fn print_something(&self) -> bool;
+    /// Whether or not this will render as something meaningful, or if it's skipped
+    /// (which will force the containing struct to also skip printing a comma
+    /// and the field name).
+    fn should_render(&self) -> bool;
+
     fn print_attribute(&self, p: &mut Printer);
 }
 
 impl<T: PrintAttribute> PrintAttribute for &T {
-    fn print_something(&self) -> bool {
-        T::print_something(self)
+    fn should_render(&self) -> bool {
+        T::should_render(self)
     }
 
     fn print_attribute(&self, p: &mut Printer) {
@@ -48,9 +52,10 @@ impl<T: PrintAttribute> PrintAttribute for &T {
     }
 }
 impl<T: PrintAttribute> PrintAttribute for Option<T> {
-    fn print_something(&self) -> bool {
-        self.as_ref().is_some_and(|x| x.print_something())
+    fn should_render(&self) -> bool {
+        self.as_ref().is_some_and(|x| x.should_render())
     }
+
     fn print_attribute(&self, p: &mut Printer) {
         if let Some(i) = self {
             T::print_attribute(i, p)
@@ -58,9 +63,10 @@ impl<T: PrintAttribute> PrintAttribute for Option<T> {
     }
 }
 impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
-    fn print_something(&self) -> bool {
-        self.is_empty() || self[0].print_something()
+    fn should_render(&self) -> bool {
+        self.is_empty() || self[0].should_render()
     }
+
     fn print_attribute(&self, p: &mut Printer) {
         let mut last_printed = false;
         p.word("[");
@@ -69,7 +75,7 @@ impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
                 p.word_space(",");
             }
             i.print_attribute(p);
-            last_printed = i.print_something();
+            last_printed = i.should_render();
         }
         p.word("]");
     }
@@ -77,7 +83,7 @@ impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
 macro_rules! print_skip {
     ($($t: ty),* $(,)?) => {$(
         impl PrintAttribute for $t {
-            fn print_something(&self) -> bool { false }
+            fn should_render(&self) -> bool { false }
             fn print_attribute(&self, _: &mut Printer) { }
         })*
     };
@@ -86,7 +92,7 @@ macro_rules! print_skip {
 macro_rules! print_disp {
     ($($t: ty),* $(,)?) => {$(
         impl PrintAttribute for $t {
-            fn print_something(&self) -> bool { true }
+            fn should_render(&self) -> bool { true }
             fn print_attribute(&self, p: &mut Printer) {
                 p.word(format!("{}", self));
             }
@@ -96,7 +102,7 @@ macro_rules! print_disp {
 macro_rules! print_debug {
     ($($t: ty),* $(,)?) => {$(
         impl PrintAttribute for $t {
-            fn print_something(&self) -> bool { true }
+            fn should_render(&self) -> bool { true }
             fn print_attribute(&self, p: &mut Printer) {
                 p.word(format!("{:?}", self));
             }
@@ -105,37 +111,39 @@ macro_rules! print_debug {
 }
 
 macro_rules! print_tup {
-    (num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* };
+    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
     () => {};
     ($t: ident $($ts: ident)*) => {
         #[allow(non_snake_case, unused)]
         impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
-            fn print_something(&self) -> bool {
+            fn should_render(&self) -> bool {
                 let ($t, $($ts),*) = self;
-                print_tup!(num_print_something $t $($ts)*) != 0
+                print_tup!(num_should_render $t $($ts)*) != 0
             }
 
             fn print_attribute(&self, p: &mut Printer) {
                 let ($t, $($ts),*) = self;
-                let parens = print_tup!(num_print_something $t $($ts)*) > 1;
+                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
                 if parens {
-                    p.word("(");
+                    p.popen();
                 }
 
-                let mut printed_anything = $t.print_something();
+                let mut printed_anything = $t.should_render();
 
                 $t.print_attribute(p);
 
                 $(
-                    if printed_anything && $ts.print_something() {
-                        p.word_space(",");
+                    if $ts.should_render() {
+                        if printed_anything {
+                            p.word_space(",");
+                        }
                         printed_anything = true;
                     }
                     $ts.print_attribute(p);
                 )*
 
                 if parens {
-                    p.word(")");
+                    p.pclose();
                 }
             }
         }
@@ -146,8 +154,8 @@ macro_rules! print_tup {
 
 print_tup!(A B C D E F G H);
 print_skip!(Span, ());
-print_disp!(Symbol, u16, bool, NonZero<u32>);
-print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
+print_disp!(u16, bool, NonZero<u32>);
+print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
 
 /// Finds attributes in sequences of attributes by pattern matching.
 ///
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 0e6b0bab082..35541bb04bd 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -9,7 +9,6 @@ use rustc_errors::{DiagCtxtHandle, Diagnostic};
 use rustc_feature::Features;
 use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId};
 use rustc_session::Session;
-use rustc_span::symbol::kw;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
 use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
@@ -338,7 +337,7 @@ impl<'sess> AttributeParser<'sess> {
                         "expr in place where literal is expected (builtin attr parsing)",
                     );
                     ast::MetaItemLit {
-                        symbol: kw::Empty,
+                        symbol: sym::dummy,
                         suffix: None,
                         kind: ast::LitKind::Err(guar),
                         span: DUMMY_SP,
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index f0cce26f4e2..a8a1460591c 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -12,7 +12,7 @@ use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, Norma
 use rustc_ast_pretty::pprust;
 use rustc_errors::DiagCtxtHandle;
 use rustc_hir::{self as hir, AttrPath};
-use rustc_span::symbol::{Ident, kw};
+use rustc_span::symbol::{Ident, kw, sym};
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 pub struct SegmentIterator<'a> {
@@ -360,7 +360,7 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit
             span,
             "expr in place where literal is expected (builtin attr parsing)",
         );
-        MetaItemLit { symbol: kw::Empty, suffix: None, kind: LitKind::Err(guar), span }
+        MetaItemLit { symbol: sym::dummy, suffix: None, kind: LitKind::Err(guar), span }
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index d1f238331d5..208d510db2e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -505,7 +505,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     let var_id =
                         self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
 
-                    Some(self.infcx.tcx.hir().name(var_id).to_string())
+                    Some(self.infcx.tcx.hir_name(var_id).to_string())
                 }
                 _ => {
                     // Might need a revision when the fields in trait RFC is implemented
@@ -1124,7 +1124,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             def_id, target_place, places
         );
         let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
-        let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
+        let expr = &self.infcx.tcx.hir_expect_expr(hir_id).kind;
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
         if let &hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
             for (captured_place, place) in
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 145137f9236..3951b467961 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -698,7 +698,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         if !matches!(k, hir::AssocItemKind::Fn { .. }) {
                             continue;
                         }
-                        if self.infcx.tcx.hir().name(hi) != self.infcx.tcx.hir().name(my_hir) {
+                        if self.infcx.tcx.hir_name(hi) != self.infcx.tcx.hir_name(my_hir) {
                             continue;
                         }
                         f_in_trait_opt = Some(hi);
diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
index 876b8f214b0..7192a889adc 100644
--- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
@@ -105,7 +105,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
                     if let Some(opaque_def_id) = opaque_def_id.as_local()
                         && let hir::OpaqueTyOrigin::FnReturn { parent, .. } =
-                            tcx.hir().expect_opaque_ty(opaque_def_id).origin
+                            tcx.hir_expect_opaque_ty(opaque_def_id).origin
                     {
                         if let Some(sugg) = impl_trait_overcapture_suggestion(
                             tcx,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index a15f9744bf3..412aaf70c3f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -343,7 +343,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
                         }
                     };
                     let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) =
-                        tcx.hir().expect_expr(self.mir_hir_id()).kind
+                        tcx.hir_expect_expr(self.mir_hir_id()).kind
                     else {
                         bug!("Closure is not defined by a closure expr");
                     };
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 191c0444c74..693d22abbe6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -69,7 +69,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let upvar_hir_id = upvars[upvar_index].get_root_variable();
         debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}");
 
-        let upvar_name = tcx.hir().name(upvar_hir_id);
+        let upvar_name = tcx.hir_name(upvar_hir_id);
         let upvar_span = tcx.hir().span(upvar_hir_id);
         debug!(
             "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}",
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index f70b17e3362..c6b29fe36fd 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -24,9 +24,9 @@ use crate::universal_regions::DefiningTy;
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// Check explicit closure signature annotation,
     /// e.g., `|x: FxIndexMap<_, &'static u32>| ...`.
-    #[instrument(skip(self, body), level = "debug")]
-    pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
-        let mir_def_id = body.source.def_id().expect_local();
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn check_signature_annotation(&mut self) {
+        let mir_def_id = self.body.source.def_id().expect_local();
 
         if !self.tcx().is_closure_like(mir_def_id.to_def_id()) {
             return;
@@ -38,9 +38,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // (e.g., the `_` in the code above) with fresh variables.
         // Then replace the bound items in the fn sig with fresh variables,
         // so that they represent the view from "inside" the closure.
-        let user_provided_sig = self.instantiate_canonical(body.span, &user_provided_poly_sig);
+        let user_provided_sig = self.instantiate_canonical(self.body.span, &user_provided_poly_sig);
         let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
-            body.span,
+            self.body.span,
             BoundRegionConversionTime::FnCall,
             user_provided_sig,
         );
@@ -66,12 +66,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 Ty::new_tup(self.tcx(), user_provided_sig.inputs()),
                 args.tupled_upvars_ty(),
                 args.coroutine_captures_by_ref_ty(),
-                self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || {
-                    RegionCtxt::Unknown
-                }),
+                self.infcx
+                    .next_region_var(RegionVariableOrigin::MiscVariable(self.body.span), || {
+                        RegionCtxt::Unknown
+                    }),
             );
 
-            let next_ty_var = || self.infcx.next_ty_var(body.span);
+            let next_ty_var = || self.infcx.next_ty_var(self.body.span);
             let output_ty = Ty::new_coroutine(
                 self.tcx(),
                 self.tcx().coroutine_for_closure(mir_def_id),
@@ -107,9 +108,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip_eq(
             // In MIR, closure args begin with an implicit `self`.
             // Also, coroutines have a resume type which may be implicitly `()`.
-            body.args_iter()
+            self.body
+                .args_iter()
                 .skip(1 + if is_coroutine_with_implicit_resume_ty { 1 } else { 0 })
-                .map(|local| &body.local_decls[local]),
+                .map(|local| &self.body.local_decls[local]),
         ) {
             self.ascribe_user_type_skip_wf(
                 arg_decl.ty,
@@ -119,7 +121,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
 
         // If the user explicitly annotated the output type, enforce it.
-        let output_decl = &body.local_decls[RETURN_PLACE];
+        let output_decl = &self.body.local_decls[RETURN_PLACE];
         self.ascribe_user_type_skip_wf(
             output_decl.ty,
             ty::UserType::new(ty::UserTypeKind::Ty(user_provided_sig.output())),
@@ -127,12 +129,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
     }
 
-    #[instrument(skip(self, body), level = "debug")]
-    pub(super) fn equate_inputs_and_outputs(
-        &mut self,
-        body: &Body<'tcx>,
-        normalized_inputs_and_output: &[Ty<'tcx>],
-    ) {
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn equate_inputs_and_outputs(&mut self, normalized_inputs_and_output: &[Ty<'tcx>]) {
         let (&normalized_output_ty, normalized_input_tys) =
             normalized_inputs_and_output.split_last().unwrap();
 
@@ -141,18 +139,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
         // Equate expected input tys with those in the MIR.
         for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
-            if argument_index + 1 >= body.local_decls.len() {
+            if argument_index + 1 >= self.body.local_decls.len() {
                 self.tcx()
                     .dcx()
-                    .span_bug(body.span, "found more normalized_input_ty than local_decls");
+                    .span_bug(self.body.span, "found more normalized_input_ty than local_decls");
             }
 
             // In MIR, argument N is stored in local N+1.
             let local = Local::from_usize(argument_index + 1);
 
-            let mir_input_ty = body.local_decls[local].ty;
+            let mir_input_ty = self.body.local_decls[local].ty;
 
-            let mir_input_span = body.local_decls[local].source_info.span;
+            let mir_input_span = self.body.local_decls[local].source_info.span;
             self.equate_normalized_input_or_output(
                 normalized_input_ty,
                 mir_input_ty,
@@ -160,8 +158,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             );
         }
 
-        if let Some(mir_yield_ty) = body.yield_ty() {
-            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
+        if let Some(mir_yield_ty) = self.body.yield_ty() {
+            let yield_span = self.body.local_decls[RETURN_PLACE].source_info.span;
             self.equate_normalized_input_or_output(
                 self.universal_regions.yield_ty.unwrap(),
                 mir_yield_ty,
@@ -169,8 +167,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             );
         }
 
-        if let Some(mir_resume_ty) = body.resume_ty() {
-            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
+        if let Some(mir_resume_ty) = self.body.resume_ty() {
+            let yield_span = self.body.local_decls[RETURN_PLACE].source_info.span;
             self.equate_normalized_input_or_output(
                 self.universal_regions.resume_ty.unwrap(),
                 mir_resume_ty,
@@ -179,8 +177,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
 
         // Return types are a bit more complex. They may contain opaque `impl Trait` types.
-        let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
-        let output_span = body.local_decls[RETURN_PLACE].source_info.span;
+        let mir_output_ty = self.body.local_decls[RETURN_PLACE].ty;
+        let output_span = self.body.local_decls[RETURN_PLACE].source_info.span;
         self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span);
     }
 
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index dcc17903002..f17ad23f4bf 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -31,7 +31,6 @@ mod trace;
 /// performed before
 pub(super) fn generate<'a, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
-    body: &Body<'tcx>,
     location_map: &DenseLocationMap,
     flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
     move_data: &MoveData<'tcx>,
@@ -51,23 +50,16 @@ pub(super) fn generate<'a, 'tcx>(
     // We do record these regions in the polonius context, since they're used to differentiate
     // relevant and boring locals, which is a key distinction used later in diagnostics.
     if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
-        let (_, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
+        let (_, boring_locals) =
+            compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
         typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
             boring_locals.into_iter().collect();
         free_regions = typeck.universal_regions.universal_regions_iter().collect();
     }
     let (relevant_live_locals, boring_locals) =
-        compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
-
-    trace::trace(
-        typeck,
-        body,
-        location_map,
-        flow_inits,
-        move_data,
-        relevant_live_locals,
-        boring_locals,
-    );
+        compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
+
+    trace::trace(typeck, location_map, flow_inits, move_data, relevant_live_locals, boring_locals);
 
     // Mark regions that should be live where they appear within rvalues or within a call: like
     // args, regions, and types.
@@ -76,7 +68,7 @@ pub(super) fn generate<'a, 'tcx>(
         &mut typeck.constraints.liveness_constraints,
         &typeck.universal_regions,
         &mut typeck.polonius_liveness,
-        body,
+        typeck.body,
     );
 }
 
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index dc35d5eb89c..7718644b9a9 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -39,17 +39,15 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
 /// this respects `#[may_dangle]` annotations).
 pub(super) fn trace<'a, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
-    body: &Body<'tcx>,
     location_map: &DenseLocationMap,
     flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
     move_data: &MoveData<'tcx>,
     relevant_live_locals: Vec<Local>,
     boring_locals: Vec<Local>,
 ) {
-    let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body);
+    let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, typeck.body);
     let cx = LivenessContext {
         typeck,
-        body,
         flow_inits,
         location_map,
         local_use_map,
@@ -69,14 +67,13 @@ pub(super) fn trace<'a, 'tcx>(
 /// Contextual state for the type-liveness coroutine.
 struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
     /// Current type-checker, giving us our inference context etc.
+    ///
+    /// This also stores the body we're currently analyzing.
     typeck: &'a mut TypeChecker<'typeck, 'tcx>,
 
     /// Defines the `PointIndex` mapping
     location_map: &'a DenseLocationMap,
 
-    /// MIR we are analyzing.
-    body: &'a Body<'tcx>,
-
     /// Mapping to/from the various indices used for initialization tracking.
     move_data: &'a MoveData<'tcx>,
 
@@ -139,7 +136,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
             self.compute_use_live_points_for(local);
             self.compute_drop_live_points_for(local);
 
-            let local_ty = self.cx.body.local_decls[local].ty;
+            let local_ty = self.cx.body().local_decls[local].ty;
 
             if !self.use_live_at.is_empty() {
                 self.cx.add_use_live_facts_for(local_ty, &self.use_live_at);
@@ -164,8 +161,8 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
     /// and can therefore safely be dropped.
     fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
         for local in boring_locals {
-            let local_ty = self.cx.body.local_decls[local].ty;
-            let local_span = self.cx.body.local_decls[local].source_info.span;
+            let local_ty = self.cx.body().local_decls[local].ty;
+            let local_span = self.cx.body().local_decls[local].source_info.span;
             let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
                 let typeck = &self.cx.typeck;
                 move || LivenessContext::compute_drop_data(typeck, local_ty, local_span)
@@ -173,7 +170,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
 
             drop_data.dropck_result.report_overflows(
                 self.cx.typeck.infcx.tcx,
-                self.cx.body.local_decls[local].source_info.span,
+                self.cx.typeck.body.local_decls[local].source_info.span,
                 local_ty,
             );
         }
@@ -202,7 +199,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
                 .var_dropped_at
                 .iter()
                 .filter_map(|&(local, location_index)| {
-                    let local_ty = self.cx.body.local_decls[local].ty;
+                    let local_ty = self.cx.body().local_decls[local].ty;
                     if relevant_live_locals.contains(&local) || !local_ty.has_free_regions() {
                         return None;
                     }
@@ -278,9 +275,9 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
 
                 let block = self.cx.location_map.to_location(block_start).block;
                 self.stack.extend(
-                    self.cx.body.basic_blocks.predecessors()[block]
+                    self.cx.body().basic_blocks.predecessors()[block]
                         .iter()
-                        .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
+                        .map(|&pred_bb| self.cx.body().terminator_loc(pred_bb))
                         .map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)),
                 );
             }
@@ -305,7 +302,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
         // Find the drops where `local` is initialized.
         for drop_point in self.cx.local_use_map.drops(local) {
             let location = self.cx.location_map.to_location(drop_point);
-            debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
+            debug_assert_eq!(self.cx.body().terminator_loc(location.block), location,);
 
             if self.cx.initialized_at_terminator(location.block, mpi)
                 && self.drop_live_at.insert(drop_point)
@@ -351,7 +348,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
         // block. One of them may be either a definition or use
         // live point.
         let term_location = self.cx.location_map.to_location(term_point);
-        debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
+        debug_assert_eq!(self.cx.body().terminator_loc(term_location.block), term_location,);
         let block = term_location.block;
         let entry_point = self.cx.location_map.entry_point(term_location.block);
         for p in (entry_point..term_point).rev() {
@@ -376,7 +373,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
             }
         }
 
-        let body = self.cx.body;
+        let body = self.cx.typeck.body;
         for &pred_block in body.basic_blocks.predecessors()[block].iter() {
             debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);
 
@@ -403,7 +400,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
                 continue;
             }
 
-            let pred_term_loc = self.cx.body.terminator_loc(pred_block);
+            let pred_term_loc = self.cx.body().terminator_loc(pred_block);
             let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc);
 
             // If the terminator of this predecessor either *assigns*
@@ -463,6 +460,9 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
 }
 
 impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
+    fn body(&self) -> &Body<'tcx> {
+        self.typeck.body
+    }
     /// Returns `true` if the local variable (or some part of it) is initialized at the current
     /// cursor position. Callers should call one of the `seek` methods immediately before to point
     /// the cursor to the desired location.
@@ -481,7 +481,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     /// DROP of some local variable will have an effect -- note that
     /// drops, as they may unwind, are always terminators.
     fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
-        self.flow_inits.seek_before_primary_effect(self.body.terminator_loc(block));
+        self.flow_inits.seek_before_primary_effect(self.body().terminator_loc(block));
         self.initialized_at_curr_loc(mpi)
     }
 
@@ -491,7 +491,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     /// **Warning:** Does not account for the result of `Call`
     /// instructions.
     fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool {
-        self.flow_inits.seek_after_primary_effect(self.body.terminator_loc(block));
+        self.flow_inits.seek_after_primary_effect(self.body().terminator_loc(block));
         self.initialized_at_curr_loc(mpi)
     }
 
@@ -526,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
             values::pretty_print_points(self.location_map, live_at.iter()),
         );
 
-        let local_span = self.body.local_decls()[dropped_local].source_info.span;
+        let local_span = self.body().local_decls()[dropped_local].source_info.span;
         let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
             let typeck = &self.typeck;
             move || Self::compute_drop_data(typeck, dropped_ty, local_span)
@@ -544,7 +544,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
 
         drop_data.dropck_result.report_overflows(
             self.typeck.infcx.tcx,
-            self.body.source_info(*drop_locations.first().unwrap()).span,
+            self.typeck.body.source_info(*drop_locations.first().unwrap()).span,
             dropped_ty,
         );
 
@@ -610,7 +610,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
             Err(ErrorGuaranteed { .. }) => {
                 // We don't run dropck on HIR, and dropck looks inside fields of
                 // types, so there's no guarantee that it succeeds. We also
-                // can't rely on the the `ErrorGuaranteed` from `fully_perform` here
+                // can't rely on the `ErrorGuaranteed` from `fully_perform` here
                 // because it comes from delay_span_bug.
                 //
                 // Do this inside of a probe because we don't particularly care (or want)
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index c1e23cb5411..9d5022f2bef 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -174,11 +174,11 @@ pub(crate) fn type_check<'a, 'tcx>(
     let mut verifier = TypeVerifier { typeck: &mut typeck, promoted, last_span: body.span };
     verifier.visit_body(body);
 
-    typeck.typeck_mir(body);
-    typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
-    typeck.check_signature_annotation(body);
+    typeck.typeck_mir();
+    typeck.equate_inputs_and_outputs(&normalized_inputs_and_output);
+    typeck.check_signature_annotation();
 
-    liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data);
+    liveness::generate(&mut typeck, &location_map, flow_inits, move_data);
 
     let opaque_type_values =
         opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
@@ -485,6 +485,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_body(&mut self, body: &Body<'tcx>) {
+        debug_assert!(std::ptr::eq(self.typeck.body, body));
         // We intentionally do not recurse into `body.required_consts` or
         // `body.mentioned_items` here as the MIR at this phase should still
         // refer to all items and we don't want to check them multiple times.
@@ -542,7 +543,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
         self.visit_body(promoted_body);
 
-        self.typeck.typeck_mir(promoted_body);
+        self.typeck.typeck_mir();
 
         self.typeck.body = parent_body;
         // Merge the outlives constraints back in, at the given location.
@@ -892,8 +893,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    #[instrument(skip(self, body), level = "debug")]
-    fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
+    #[instrument(skip(self), level = "debug")]
+    fn check_stmt(&mut self, stmt: &Statement<'tcx>, location: Location) {
         let tcx = self.tcx();
         debug!("stmt kind: {:?}", stmt.kind);
         match &stmt.kind {
@@ -916,11 +917,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     Some(l)
-                        if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) =>
+                        if matches!(
+                            self.body.local_decls[l].local_info(),
+                            LocalInfo::AggregateTemp
+                        ) =>
                     {
                         ConstraintCategory::Usage
                     }
-                    Some(l) if !body.local_decls[l].is_user_variable() => {
+                    Some(l) if !self.body.local_decls[l].is_user_variable() => {
                         ConstraintCategory::Boring
                     }
                     _ => ConstraintCategory::Assignment,
@@ -928,14 +932,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 debug!(
                     "assignment category: {:?} {:?}",
                     category,
-                    place.as_local().map(|l| &body.local_decls[l])
+                    place.as_local().map(|l| &self.body.local_decls[l])
                 );
 
-                let place_ty = place.ty(body, tcx).ty;
+                let place_ty = place.ty(self.body, tcx).ty;
                 debug!(?place_ty);
                 let place_ty = self.normalize(place_ty, location);
                 debug!("place_ty normalized: {:?}", place_ty);
-                let rv_ty = rv.ty(body, tcx);
+                let rv_ty = rv.ty(self.body, tcx);
                 debug!(?rv_ty);
                 let rv_ty = self.normalize(rv_ty, location);
                 debug!("normalized rv_ty: {:?}", rv_ty);
@@ -972,7 +976,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
                 }
 
-                self.check_rvalue(body, rv, location);
+                self.check_rvalue(rv, location);
                 if !self.unsized_feature_enabled() {
                     let trait_ref = ty::TraitRef::new(
                         tcx,
@@ -987,7 +991,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
             StatementKind::AscribeUserType(box (place, projection), variance) => {
-                let place_ty = place.ty(body, tcx).ty;
+                let place_ty = place.ty(self.body, tcx).ty;
                 if let Err(terr) = self.relate_type_and_user_type(
                     place_ty,
                     *variance,
@@ -1029,13 +1033,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, body, term_location), level = "debug")]
-    fn check_terminator(
-        &mut self,
-        body: &Body<'tcx>,
-        term: &Terminator<'tcx>,
-        term_location: Location,
-    ) {
+    #[instrument(skip(self, term_location), level = "debug")]
+    fn check_terminator(&mut self, term: &Terminator<'tcx>, term_location: Location) {
         let tcx = self.tcx();
         debug!("terminator kind: {:?}", term.kind);
         match &term.kind {
@@ -1055,7 +1054,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             TerminatorKind::SwitchInt { discr, .. } => {
                 self.check_operand(discr, term_location);
 
-                let switch_ty = discr.ty(body, tcx);
+                let switch_ty = discr.ty(self.body, tcx);
                 if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
                     span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
                 }
@@ -1074,7 +1073,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     self.check_operand(&arg.node, term_location);
                 }
 
-                let func_ty = func.ty(body, tcx);
+                let func_ty = func.ty(self.body, tcx);
                 debug!("func_ty.kind: {:?}", func_ty.kind());
 
                 let sig = match func_ty.kind() {
@@ -1142,7 +1141,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
 
                 if let TerminatorKind::Call { destination, target, .. } = term.kind {
-                    self.check_call_dest(body, term, &sig, destination, target, term_location);
+                    self.check_call_dest(term, &sig, destination, target, term_location);
                 }
 
                 // The ordinary liveness rules will ensure that all
@@ -1157,21 +1156,21 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     self.constraints.liveness_constraints.add_location(region_vid, term_location);
                 }
 
-                self.check_call_inputs(body, term, func, &sig, args, term_location, call_source);
+                self.check_call_inputs(term, func, &sig, args, term_location, call_source);
             }
             TerminatorKind::Assert { cond, msg, .. } => {
                 self.check_operand(cond, term_location);
 
-                let cond_ty = cond.ty(body, tcx);
+                let cond_ty = cond.ty(self.body, tcx);
                 if cond_ty != tcx.types.bool {
                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
                 }
 
                 if let AssertKind::BoundsCheck { len, index } = &**msg {
-                    if len.ty(body, tcx) != tcx.types.usize {
+                    if len.ty(self.body, tcx) != tcx.types.usize {
                         span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
                     }
-                    if index.ty(body, tcx) != tcx.types.usize {
+                    if index.ty(self.body, tcx) != tcx.types.usize {
                         span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
                     }
                 }
@@ -1179,10 +1178,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             TerminatorKind::Yield { value, resume_arg, .. } => {
                 self.check_operand(value, term_location);
 
-                match body.yield_ty() {
+                match self.body.yield_ty() {
                     None => span_mirbug!(self, term, "yield in non-coroutine"),
                     Some(ty) => {
-                        let value_ty = value.ty(body, tcx);
+                        let value_ty = value.ty(self.body, tcx);
                         if let Err(terr) = self.sub_types(
                             value_ty,
                             ty,
@@ -1201,10 +1200,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
                 }
 
-                match body.resume_ty() {
+                match self.body.resume_ty() {
                     None => span_mirbug!(self, term, "yield in non-coroutine"),
                     Some(ty) => {
-                        let resume_ty = resume_arg.ty(body, tcx);
+                        let resume_ty = resume_arg.ty(self.body, tcx);
                         if let Err(terr) = self.sub_types(
                             ty,
                             resume_ty.ty,
@@ -1228,7 +1227,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
     fn check_call_dest(
         &mut self,
-        body: &Body<'tcx>,
         term: &Terminator<'tcx>,
         sig: &ty::FnSig<'tcx>,
         destination: Place<'tcx>,
@@ -1238,7 +1236,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let tcx = self.tcx();
         match target {
             Some(_) => {
-                let dest_ty = destination.ty(body, tcx).ty;
+                let dest_ty = destination.ty(self.body, tcx).ty;
                 let dest_ty = self.normalize(dest_ty, term_location);
                 let category = match destination.as_local() {
                     Some(RETURN_PLACE) => {
@@ -1254,7 +1252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             ConstraintCategory::Return(ReturnConstraint::Normal)
                         }
                     }
-                    Some(l) if !body.local_decls[l].is_user_variable() => {
+                    Some(l) if !self.body.local_decls[l].is_user_variable() => {
                         ConstraintCategory::Boring
                     }
                     // The return type of a call is interesting for diagnostics.
@@ -1295,10 +1293,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))]
+    #[instrument(level = "debug", skip(self, term, func, term_location, call_source))]
     fn check_call_inputs(
         &mut self,
-        body: &Body<'tcx>,
         term: &Terminator<'tcx>,
         func: &Operand<'tcx>,
         sig: &ty::FnSig<'tcx>,
@@ -1310,7 +1307,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
 
-        let func_ty = func.ty(body, self.infcx.tcx);
+        let func_ty = func.ty(self.body, self.infcx.tcx);
         if let ty::FnDef(def_id, _) = *func_ty.kind() {
             // Some of the SIMD intrinsics are special: they need a particular argument to be a
             // constant. (Eventually this should use const-generics, but those are not up for the
@@ -1334,7 +1331,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         debug!(?func_ty);
 
         for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
-            let op_arg_ty = op_arg.node.ty(body, self.tcx());
+            let op_arg_ty = op_arg.node.ty(self.body, self.tcx());
 
             let op_arg_ty = self.normalize(op_arg_ty, term_location);
             let category = if call_source.from_hir_call() {
@@ -1358,16 +1355,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) {
+    fn check_iscleanup(&mut self, block_data: &BasicBlockData<'tcx>) {
         let is_cleanup = block_data.is_cleanup;
         self.last_span = block_data.terminator().source_info.span;
         match block_data.terminator().kind {
             TerminatorKind::Goto { target } => {
-                self.assert_iscleanup(body, block_data, target, is_cleanup)
+                self.assert_iscleanup(block_data, target, is_cleanup)
             }
             TerminatorKind::SwitchInt { ref targets, .. } => {
                 for target in targets.all_targets() {
-                    self.assert_iscleanup(body, block_data, *target, is_cleanup);
+                    self.assert_iscleanup(block_data, *target, is_cleanup);
                 }
             }
             TerminatorKind::UnwindResume => {
@@ -1399,55 +1396,48 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 if is_cleanup {
                     span_mirbug!(self, block_data, "yield in cleanup block")
                 }
-                self.assert_iscleanup(body, block_data, resume, is_cleanup);
+                self.assert_iscleanup(block_data, resume, is_cleanup);
                 if let Some(drop) = drop {
-                    self.assert_iscleanup(body, block_data, drop, is_cleanup);
+                    self.assert_iscleanup(block_data, drop, is_cleanup);
                 }
             }
             TerminatorKind::Unreachable => {}
             TerminatorKind::Drop { target, unwind, .. }
             | TerminatorKind::Assert { target, unwind, .. } => {
-                self.assert_iscleanup(body, block_data, target, is_cleanup);
-                self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
+                self.assert_iscleanup(block_data, target, is_cleanup);
+                self.assert_iscleanup_unwind(block_data, unwind, is_cleanup);
             }
             TerminatorKind::Call { ref target, unwind, .. } => {
                 if let &Some(target) = target {
-                    self.assert_iscleanup(body, block_data, target, is_cleanup);
+                    self.assert_iscleanup(block_data, target, is_cleanup);
                 }
-                self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
+                self.assert_iscleanup_unwind(block_data, unwind, is_cleanup);
             }
             TerminatorKind::FalseEdge { real_target, imaginary_target } => {
-                self.assert_iscleanup(body, block_data, real_target, is_cleanup);
-                self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup);
+                self.assert_iscleanup(block_data, real_target, is_cleanup);
+                self.assert_iscleanup(block_data, imaginary_target, is_cleanup);
             }
             TerminatorKind::FalseUnwind { real_target, unwind } => {
-                self.assert_iscleanup(body, block_data, real_target, is_cleanup);
-                self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
+                self.assert_iscleanup(block_data, real_target, is_cleanup);
+                self.assert_iscleanup_unwind(block_data, unwind, is_cleanup);
             }
             TerminatorKind::InlineAsm { ref targets, unwind, .. } => {
                 for &target in targets {
-                    self.assert_iscleanup(body, block_data, target, is_cleanup);
+                    self.assert_iscleanup(block_data, target, is_cleanup);
                 }
-                self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
+                self.assert_iscleanup_unwind(block_data, unwind, is_cleanup);
             }
         }
     }
 
-    fn assert_iscleanup(
-        &mut self,
-        body: &Body<'tcx>,
-        ctxt: &dyn fmt::Debug,
-        bb: BasicBlock,
-        iscleanuppad: bool,
-    ) {
-        if body[bb].is_cleanup != iscleanuppad {
+    fn assert_iscleanup(&mut self, ctxt: &dyn fmt::Debug, bb: BasicBlock, iscleanuppad: bool) {
+        if self.body[bb].is_cleanup != iscleanuppad {
             span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad);
         }
     }
 
     fn assert_iscleanup_unwind(
         &mut self,
-        body: &Body<'tcx>,
         ctxt: &dyn fmt::Debug,
         unwind: UnwindAction,
         is_cleanup: bool,
@@ -1457,7 +1447,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 if is_cleanup {
                     span_mirbug!(self, ctxt, "unwind on cleanup block")
                 }
-                self.assert_iscleanup(body, ctxt, unwind, true);
+                self.assert_iscleanup(ctxt, unwind, true);
             }
             UnwindAction::Continue => {
                 if is_cleanup {
@@ -1468,8 +1458,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
-        match body.local_kind(local) {
+    fn check_local(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
+        match self.body.local_kind(local) {
             LocalKind::ReturnPointer | LocalKind::Arg => {
                 // return values of normal functions are required to be
                 // sized by typeck, but return values of ADT constructors are
@@ -1598,23 +1588,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, body), level = "debug")]
-    fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
+    #[instrument(skip(self), level = "debug")]
+    fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         let tcx = self.tcx();
-        let span = body.source_info(location).span;
+        let span = self.body.source_info(location).span;
 
         match rvalue {
             Rvalue::Aggregate(ak, ops) => {
                 for op in ops {
                     self.check_operand(op, location);
                 }
-                self.check_aggregate_rvalue(body, rvalue, ak, ops, location)
+                self.check_aggregate_rvalue(rvalue, ak, ops, location)
             }
 
             Rvalue::Repeat(operand, len) => {
                 self.check_operand(operand, location);
 
-                let array_ty = rvalue.ty(body.local_decls(), tcx);
+                let array_ty = rvalue.ty(self.body.local_decls(), tcx);
                 self.prove_predicate(
                     ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())),
                     Locations::Single(location),
@@ -1633,7 +1623,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                         Operand::Move(place) => {
                             // Make sure that repeated elements implement `Copy`.
-                            let ty = place.ty(body, tcx).ty;
+                            let ty = place.ty(self.body, tcx).ty;
                             let trait_ref = ty::TraitRef::new(
                                 tcx,
                                 tcx.require_lang_item(LangItem::Copy, Some(span)),
@@ -1688,7 +1678,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 match *cast_kind {
                     CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => {
                         let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
-                        let src_ty = op.ty(body, tcx);
+                        let src_ty = op.ty(self.body, tcx);
                         let mut src_sig = src_ty.fn_sig(tcx);
                         if let ty::FnDef(def_id, _) = src_ty.kind()
                             && let ty::FnPtr(_, target_hdr) = *ty.kind()
@@ -1697,7 +1687,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             && let Some(safe_sig) = tcx.adjust_target_feature_sig(
                                 *def_id,
                                 src_sig,
-                                body.source.def_id(),
+                                self.body.source.def_id(),
                             )
                         {
                             src_sig = safe_sig;
@@ -1790,7 +1780,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         PointerCoercion::ClosureFnPointer(safety),
                         coercion_source,
                     ) => {
-                        let sig = match op.ty(body, tcx).kind() {
+                        let sig = match op.ty(self.body, tcx).kind() {
                             ty::Closure(_, args) => args.as_closure().sig(),
                             _ => bug!(),
                         };
@@ -1819,7 +1809,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         PointerCoercion::UnsafeFnPointer,
                         coercion_source,
                     ) => {
-                        let fn_sig = op.ty(body, tcx).fn_sig(tcx);
+                        let fn_sig = op.ty(self.body, tcx).fn_sig(tcx);
 
                         // The type that we see in the fcx is like
                         // `foo::<'a, 'b>`, where `foo` is the path to a
@@ -1853,7 +1843,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let trait_ref = ty::TraitRef::new(
                             tcx,
                             tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
-                            [op.ty(body, tcx), ty],
+                            [op.ty(self.body, tcx), ty],
                         );
 
                         let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
@@ -1879,7 +1869,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             _ => panic!("Invalid dyn* cast_ty"),
                         };
 
-                        let self_ty = op.ty(body, tcx);
+                        let self_ty = op.ty(self.body, tcx);
 
                         let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
                         self.prove_predicates(
@@ -1906,7 +1896,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         PointerCoercion::MutToConstPointer,
                         coercion_source,
                     ) => {
-                        let ty::RawPtr(ty_from, hir::Mutability::Mut) = op.ty(body, tcx).kind()
+                        let ty::RawPtr(ty_from, hir::Mutability::Mut) =
+                            op.ty(self.body, tcx).kind()
                         else {
                             span_mirbug!(self, rvalue, "unexpected base type for cast {:?}", ty,);
                             return;
@@ -1934,7 +1925,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
 
                     CastKind::PointerCoercion(PointerCoercion::ArrayToPointer, coercion_source) => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
 
                         let opt_ty_elem_mut = match ty_from.kind() {
                             ty::RawPtr(array_ty, array_mut) => match array_ty.kind() {
@@ -1997,7 +1988,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
 
                     CastKind::PointerExposeProvenance => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2015,7 +2006,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
 
                     CastKind::PointerWithExposedProvenance => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2032,7 +2023,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::IntToInt => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2049,7 +2040,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::IntToFloat => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2066,7 +2057,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::FloatToInt => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2083,7 +2074,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::FloatToFloat => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2100,7 +2091,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::FnPtrToPtr => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2117,7 +2108,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::PtrToPtr => {
-                        let ty_from = op.ty(body, tcx);
+                        let ty_from = op.ty(self.body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
@@ -2193,7 +2184,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
 
             Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
-                self.add_reborrow_constraint(body, location, *region, borrowed_place);
+                self.add_reborrow_constraint(location, *region, borrowed_place);
             }
 
             Rvalue::BinaryOp(
@@ -2203,12 +2194,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.check_operand(left, location);
                 self.check_operand(right, location);
 
-                let ty_left = left.ty(body, tcx);
+                let ty_left = left.ty(self.body, tcx);
                 match ty_left.kind() {
                     // Types with regions are comparable if they have a common super-type.
                     ty::RawPtr(_, _) | ty::FnPtr(..) => {
-                        let ty_right = right.ty(body, tcx);
-                        let common_ty = self.infcx.next_ty_var(body.source_info(location).span);
+                        let ty_right = right.ty(self.body, tcx);
+                        let common_ty =
+                            self.infcx.next_ty_var(self.body.source_info(location).span);
                         self.sub_types(
                             ty_left,
                             common_ty,
@@ -2237,7 +2229,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     // For types with no regions we can just check that the
                     // both operands have the same type.
                     ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_)
-                        if ty_left == right.ty(body, tcx) => {}
+                        if ty_left == right.ty(self.body, tcx) => {}
                     // Other types are compared by trait methods, not by
                     // `Rvalue::BinaryOp`.
                     _ => span_mirbug!(
@@ -2245,7 +2237,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         rvalue,
                         "unexpected comparison types {:?} and {:?}",
                         ty_left,
-                        right.ty(body, tcx)
+                        right.ty(self.body, tcx)
                     ),
                 }
             }
@@ -2326,7 +2318,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
     fn check_aggregate_rvalue(
         &mut self,
-        body: &Body<'tcx>,
         rvalue: &Rvalue<'tcx>,
         aggregate_kind: &AggregateKind<'tcx>,
         operands: &IndexSlice<FieldIdx, Operand<'tcx>>,
@@ -2359,7 +2350,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     continue;
                 }
             };
-            let operand_ty = operand.ty(body, tcx);
+            let operand_ty = operand.ty(self.body, tcx);
             let operand_ty = self.normalize(operand_ty, location);
 
             if let Err(terr) = self.sub_types(
@@ -2389,7 +2380,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// - `borrowed_place`: the place `P` being borrowed
     fn add_reborrow_constraint(
         &mut self,
-        body: &Body<'tcx>,
         location: Location,
         borrow_region: ty::Region<'tcx>,
         borrowed_place: &Place<'tcx>,
@@ -2428,7 +2418,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let def = self.body.source.def_id().expect_local();
         let upvars = tcx.closure_captures(def);
         let field =
-            path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), body);
+            path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), self.body);
         let category = if let Some(field) = field {
             ConstraintCategory::ClosureUpvar(field)
         } else {
@@ -2440,7 +2430,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
             match elem {
                 ProjectionElem::Deref => {
-                    let base_ty = base.ty(body, tcx).ty;
+                    let base_ty = base.ty(self.body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.kind() {
@@ -2449,7 +2439,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 sup: ref_region.as_var(),
                                 sub: borrow_region.as_var(),
                                 locations: location.to_locations(),
-                                span: location.to_locations().span(body),
+                                span: location.to_locations().span(self.body),
                                 category,
                                 variance_info: ty::VarianceDiagInfo::default(),
                                 from_closure: false,
@@ -2634,27 +2624,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         tcx.predicates_of(def_id).instantiate(tcx, args)
     }
 
-    #[instrument(skip(self, body), level = "debug")]
-    fn typeck_mir(&mut self, body: &Body<'tcx>) {
-        self.last_span = body.span;
-        debug!(?body.span);
+    #[instrument(skip(self), level = "debug")]
+    fn typeck_mir(&mut self) {
+        self.last_span = self.body.span;
+        debug!(?self.body.span);
 
-        for (local, local_decl) in body.local_decls.iter_enumerated() {
-            self.check_local(body, local, local_decl);
+        for (local, local_decl) in self.body.local_decls.iter_enumerated() {
+            self.check_local(local, local_decl);
         }
 
-        for (block, block_data) in body.basic_blocks.iter_enumerated() {
+        for (block, block_data) in self.body.basic_blocks.iter_enumerated() {
             let mut location = Location { block, statement_index: 0 };
             for stmt in &block_data.statements {
                 if !stmt.source_info.span.is_dummy() {
                     self.last_span = stmt.source_info.span;
                 }
-                self.check_stmt(body, stmt, location);
+                self.check_stmt(stmt, location);
                 location.statement_index += 1;
             }
 
-            self.check_terminator(body, block_data.terminator(), location);
-            self.check_iscleanup(body, block_data);
+            self.check_terminator(block_data.terminator(), location);
+            self.check_iscleanup(block_data);
         }
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/opaque_types.rs b/compiler/rustc_borrowck/src/type_check/opaque_types.rs
index 17482cc0cbd..94b3d0c2bbf 100644
--- a/compiler/rustc_borrowck/src/type_check/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/type_check/opaque_types.rs
@@ -180,6 +180,7 @@ pub(super) fn take_opaques_and_register_member_constraints<'tcx>(
 /// // Equivalent to:
 /// # mod dummy { use super::*;
 /// type FooReturn<'a, T> = impl Foo<'a>;
+/// #[define_opaque(FooReturn)]
 /// fn foo<'a, T>(x: &'a u32, y: T) -> FooReturn<'a, T> {
 ///   (x, y)
 /// }
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index b5f4f2efd1f..1289d21308b 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -3,10 +3,6 @@ name = "rustc_builtin_macros"
 version = "0.0.0"
 edition = "2024"
 
-
-[lints.rust]
-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(llvm_enzyme)'] }
-
 [lib]
 doctest = false
 
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 4cac7cb93f5..3f03834f8d7 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -75,9 +75,10 @@ builtin_macros_autodiff_mode = unknown Mode: `{$mode}`. Use `Forward` or `Revers
 builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode
 builtin_macros_autodiff_not_build = this rustc version does not support autodiff
 builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found}
+builtin_macros_autodiff_ret_activity = invalid return activity {$act} in {$mode} Mode
 builtin_macros_autodiff_ty_activity = {$act} can not be used for this type
-
 builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}`
+
 builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
     .label = not applicable here
     .label2 = not a `struct`, `enum` or `union`
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 78bf2195975..1c1b2c88f76 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -88,6 +88,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
         generics: Generics::default(),
         contract: None,
         body,
+        define_opaque: None,
     }));
 
     let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 7b5c4a159b0..dcd3c1ce8d9 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -8,7 +8,8 @@ mod llvm_enzyme {
     use std::string::String;
 
     use rustc_ast::expand::autodiff_attrs::{
-        AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ty_for_activity,
+        AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
+        valid_ty_for_activity,
     };
     use rustc_ast::ptr::P;
     use rustc_ast::token::{Token, TokenKind};
@@ -247,6 +248,7 @@ mod llvm_enzyme {
             generics: Generics::default(),
             contract: None,
             body: Some(d_body),
+            define_opaque: None,
         });
         let mut rustc_ad_attr =
             P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff)));
@@ -576,6 +578,8 @@ mod llvm_enzyme {
     //
     // Error handling: If the user provides an invalid configuration (incorrect numbers, types, or
     // both), we emit an error and return the original signature. This allows us to continue parsing.
+    // FIXME(Sa4dUs): make individual activities' span available so errors
+    // can point to only the activity instead of the entire attribute
     fn gen_enzyme_decl(
         ecx: &ExtCtxt<'_>,
         sig: &ast::FnSig,
@@ -623,10 +627,22 @@ mod llvm_enzyme {
                 errors = true;
             }
         }
+
+        if has_ret && !valid_ret_activity(x.mode, x.ret_activity) {
+            dcx.emit_err(errors::AutoDiffInvalidRetAct {
+                span,
+                mode: x.mode.to_string(),
+                act: x.ret_activity.to_string(),
+            });
+            // We don't set `errors = true` to avoid annoying type errors relative
+            // to the expanded macro type signature
+        }
+
         if errors {
             // This is not the right signature, but we can continue parsing.
             return (sig.clone(), new_inputs, idents, true);
         }
+
         let unsafe_activities = x
             .input_activity
             .iter()
diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs
new file mode 100644
index 00000000000..9777e772cf2
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/define_opaque.rs
@@ -0,0 +1,54 @@
+use rustc_ast::{DUMMY_NODE_ID, ast};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::Span;
+
+pub(crate) fn expand(
+    ecx: &mut ExtCtxt<'_>,
+    _expand_span: Span,
+    meta_item: &ast::MetaItem,
+    mut item: Annotatable,
+) -> Vec<Annotatable> {
+    let define_opaque = match &mut item {
+        Annotatable::Item(p) => match &mut p.kind {
+            ast::ItemKind::Fn(f) => Some(&mut f.define_opaque),
+            _ => None,
+        },
+        Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind {
+            ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaque),
+            _ => None,
+        },
+        Annotatable::Stmt(s) => match &mut s.kind {
+            ast::StmtKind::Item(p) => match &mut p.kind {
+                ast::ItemKind::Fn(f) => Some(&mut f.define_opaque),
+                _ => None,
+            },
+            _ => None,
+        },
+        _ => None,
+    };
+
+    let Some(list) = meta_item.meta_item_list() else {
+        ecx.dcx().span_err(meta_item.span, "expected list of type aliases");
+        return vec![item];
+    };
+
+    if let Some(define_opaque) = define_opaque {
+        *define_opaque = Some(
+            list.iter()
+                .filter_map(|entry| match entry {
+                    ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => {
+                        Some((DUMMY_NODE_ID, meta_item.path.clone()))
+                    }
+                    _ => {
+                        ecx.dcx().span_err(entry.span(), "expected path to type alias");
+                        None
+                    }
+                })
+                .collect(),
+        );
+    } else {
+        ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types");
+    }
+
+    vec![item]
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 5402b5a1ae9..03ee59de70e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1040,6 +1040,7 @@ impl<'a> MethodDef<'a> {
                 generics: fn_generics,
                 contract: None,
                 body: Some(body_block),
+                define_opaque: None,
             })),
             tokens: None,
         })
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index ab1e0d8ee89..30597944124 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -186,6 +186,15 @@ mod autodiff {
     }
 
     #[derive(Diagnostic)]
+    #[diag(builtin_macros_autodiff_ret_activity)]
+    pub(crate) struct AutoDiffInvalidRetAct {
+        #[primary_span]
+        pub(crate) span: Span,
+        pub(crate) mode: String,
+        pub(crate) act: String,
+    }
+
+    #[derive(Diagnostic)]
     #[diag(builtin_macros_autodiff_mode)]
     pub(crate) struct AutoDiffInvalidMode {
         #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 8fdbbf8e704..90d79235820 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -83,6 +83,7 @@ impl AllocFnFactory<'_, '_> {
             generics: Generics::default(),
             contract: None,
             body,
+            define_opaque: None,
         }));
         let item = self.cx.item(
             self.span,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index c23ce1e5e4a..1defd3867a0 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -38,6 +38,7 @@ mod compile_error;
 mod concat;
 mod concat_bytes;
 mod concat_idents;
+mod define_opaque;
 mod derive;
 mod deriving;
 mod edition_panic;
@@ -113,6 +114,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
+        define_opaque: define_opaque::expand,
         derive: derive::Expander { is_const: false },
         derive_const: derive::Expander { is_const: true },
         global_allocator: global_allocator::expand,
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 472e16e62d5..768b459ec5e 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -346,6 +346,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
         generics: ast::Generics::default(),
         contract: None,
         body: Some(main_body),
+        define_opaque: None,
     }));
 
     // Honor the reexport_test_harness_main attribute
diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
index 2e08fbca8ef..95d58b90e79 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-72793.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
@@ -2,23 +2,21 @@
 
 #![feature(type_alias_impl_trait)]
 
-mod helper {
-    pub trait T {
-        type Item;
-    }
+pub trait T {
+    type Item;
+}
 
-    pub type Alias<'a> = impl T<Item = &'a ()>;
+pub type Alias<'a> = impl T<Item = &'a ()>;
 
-    struct S;
-    impl<'a> T for &'a S {
-        type Item = &'a ();
-    }
+struct S;
+impl<'a> T for &'a S {
+    type Item = &'a ();
+}
 
-    pub fn filter_positive<'a>() -> Alias<'a> {
-        &S
-    }
+#[define_opaque(Alias)]
+pub fn filter_positive<'a>() -> Alias<'a> {
+    &S
 }
-use helper::*;
 
 fn with_positive(fun: impl Fn(Alias<'_>)) {
     fun(filter_positive());
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index a3f43744875..06939beb374 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -176,13 +176,9 @@ impl CodegenBackend for CraneliftCodegenBackend {
         }
     }
 
-    fn target_features_cfg(
-        &self,
-        sess: &Session,
-        _allow_unstable: bool,
-    ) -> Vec<rustc_span::Symbol> {
+    fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
         // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
-        if sess.target.arch == "x86_64" && sess.target.os != "none" {
+        let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" {
             // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
             vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")]
         } else if sess.target.arch == "aarch64" {
@@ -196,7 +192,10 @@ impl CodegenBackend for CraneliftCodegenBackend {
             }
         } else {
             vec![]
-        }
+        };
+        // FIXME do `unstable_target_features` properly
+        let unstable_target_features = target_features.clone();
+        (target_features, unstable_target_features)
     }
 
     fn print_version(&self) {
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 4e8c8aaaf5c..6eae0c24f48 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -48,7 +48,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     for feature in sess.opts.cg.target_feature.split(',') {
         if let Some(feature) = feature.strip_prefix('+') {
             all_rust_features.extend(
-                UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
+                UnordSet::from(sess.target.implied_target_features(feature))
                     .to_sorted_stable_ord()
                     .iter()
                     .map(|&&s| (true, s)),
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index f090597f953..d478b2af46c 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -259,8 +259,8 @@ impl CodegenBackend for GccCodegenBackend {
             .join(sess)
     }
 
-    fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
-        target_features_cfg(sess, allow_unstable, &self.target_info)
+    fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
+        target_features_cfg(sess, &self.target_info)
     }
 }
 
@@ -486,35 +486,41 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
 /// Returns the features that should be set in `cfg(target_feature)`.
 fn target_features_cfg(
     sess: &Session,
-    allow_unstable: bool,
     target_info: &LockedTargetInfo,
-) -> Vec<Symbol> {
+) -> (Vec<Symbol>, Vec<Symbol>) {
     // TODO(antoyo): use global_gcc_features.
-    sess.target
-        .rust_target_features()
-        .iter()
-        .filter_map(|&(feature, gate, _)| {
-            if allow_unstable
-                || (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
-            {
-                Some(feature)
-            } else {
-                None
-            }
-        })
-        .filter(|feature| {
-            // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
-            if *feature == "neon" {
-                return false;
-            }
-            target_info.cpu_supports(feature)
-            /*
-              adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
-              avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
-              bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
-              sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
-            */
-        })
-        .map(Symbol::intern)
-        .collect()
+    let f = |allow_unstable| {
+        sess.target
+            .rust_target_features()
+            .iter()
+            .filter_map(|&(feature, gate, _)| {
+                if allow_unstable
+                    || (gate.in_cfg()
+                        && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
+                {
+                    Some(feature)
+                } else {
+                    None
+                }
+            })
+            .filter(|feature| {
+                // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
+                if *feature == "neon" {
+                    return false;
+                }
+                target_info.cpu_supports(feature)
+                /*
+                  adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
+                  avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
+                  bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
+                  sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
+                */
+            })
+            .map(Symbol::intern)
+            .collect()
+    };
+
+    let target_features = f(false);
+    let unstable_target_features = f(true);
+    (target_features, unstable_target_features)
 }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 2f3c8c75b0b..f622646a5d9 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -340,8 +340,8 @@ impl CodegenBackend for LlvmCodegenBackend {
         llvm_util::print_version();
     }
 
-    fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
-        target_features_cfg(sess, allow_unstable)
+    fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
+        target_features_cfg(sess)
     }
 
     fn codegen_crate<'tcx>(
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 5cc4f4ab9e6..4a166b0872d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -306,45 +306,44 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
 /// Must express features in the way Rust understands them.
 ///
 /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
-pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
-    let mut features: FxHashSet<Symbol> = Default::default();
-
+pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
     // Add base features for the target.
     // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
     // The reason is that if LLVM considers a feature implied but we do not, we don't want that to
     // show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of
-    // the target CPU, that is still expanded to target features (with all their implied features) by
-    // LLVM.
+    // the target CPU, that is still expanded to target features (with all their implied features)
+    // by LLVM.
     let target_machine = create_informational_target_machine(sess, true);
-    // Compute which of the known target features are enabled in the 'base' target machine.
-    // We only consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
-    features.extend(
-        sess.target
-            .rust_target_features()
-            .iter()
-            .filter(|(feature, _, _)| {
-                // skip checking special features, as LLVM may not understand them
-                if RUSTC_SPECIAL_FEATURES.contains(feature) {
-                    return true;
-                }
-                // check that all features in a given smallvec are enabled
-                if let Some(feat) = to_llvm_features(sess, feature) {
-                    for llvm_feature in feat {
-                        let cstr = SmallCStr::new(llvm_feature);
-                        if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) }
-                        {
-                            return false;
-                        }
+    // Compute which of the known target features are enabled in the 'base' target machine. We only
+    // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
+    let mut features: FxHashSet<Symbol> = sess
+        .target
+        .rust_target_features()
+        .iter()
+        .filter(|(feature, _, _)| {
+            // skip checking special features, as LLVM may not understand them
+            if RUSTC_SPECIAL_FEATURES.contains(feature) {
+                return true;
+            }
+            if let Some(feat) = to_llvm_features(sess, feature) {
+                for llvm_feature in feat {
+                    let cstr = SmallCStr::new(llvm_feature);
+                    // `LLVMRustHasFeature` is moderately expensive. On targets with many
+                    // features (e.g. x86) these calls take a non-trivial fraction of runtime
+                    // when compiling very small programs.
+                    if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
+                        return false;
                     }
-                    true
-                } else {
-                    false
                 }
-            })
-            .map(|(feature, _, _)| Symbol::intern(feature)),
-    );
+                true
+            } else {
+                false
+            }
+        })
+        .map(|(feature, _, _)| Symbol::intern(feature))
+        .collect();
 
-    // Add enabled features
+    // Add enabled and remove disabled features.
     for (enabled, feature) in
         sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
             Some('+') => Some((true, Symbol::intern(&s[1..]))),
@@ -360,7 +359,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
             #[allow(rustc::potential_query_instability)]
             features.extend(
                 sess.target
-                    .implied_target_features(std::iter::once(feature.as_str()))
+                    .implied_target_features(feature.as_str())
                     .iter()
                     .map(|s| Symbol::intern(s)),
             );
@@ -371,11 +370,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
             // `features.contains` below.
             #[allow(rustc::potential_query_instability)]
             features.retain(|f| {
-                if sess
-                    .target
-                    .implied_target_features(std::iter::once(f.as_str()))
-                    .contains(&feature.as_str())
-                {
+                if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
                     // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
                     // remove `f`. (This is the standard logical contraposition principle.)
                     false
@@ -387,25 +382,31 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
         }
     }
 
-    // Filter enabled features based on feature gates
-    sess.target
-        .rust_target_features()
-        .iter()
-        .filter_map(|(feature, gate, _)| {
-            // The `allow_unstable` set is used by rustc internally to determined which target
-            // features are truly available, so we want to return even perma-unstable "forbidden"
-            // features.
-            if allow_unstable
-                || (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
-            {
-                Some(*feature)
-            } else {
-                None
-            }
-        })
-        .filter(|feature| features.contains(&Symbol::intern(feature)))
-        .map(|feature| Symbol::intern(feature))
-        .collect()
+    // Filter enabled features based on feature gates.
+    let f = |allow_unstable| {
+        sess.target
+            .rust_target_features()
+            .iter()
+            .filter_map(|(feature, gate, _)| {
+                // The `allow_unstable` set is used by rustc internally to determined which target
+                // features are truly available, so we want to return even perma-unstable
+                // "forbidden" features.
+                if allow_unstable
+                    || (gate.in_cfg()
+                        && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
+                {
+                    Some(Symbol::intern(feature))
+                } else {
+                    None
+                }
+            })
+            .filter(|feature| features.contains(&feature))
+            .collect()
+    };
+
+    let target_features = f(false);
+    let unstable_target_features = f(true);
+    (target_features, unstable_target_features)
 }
 
 pub(crate) fn print_version() {
@@ -682,7 +683,7 @@ pub(crate) fn global_llvm_features(
         for feature in sess.opts.cg.target_feature.split(',') {
             if let Some(feature) = feature.strip_prefix('+') {
                 all_rust_features.extend(
-                    UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
+                    UnordSet::from(sess.target.implied_target_features(feature))
                         .to_sorted_stable_ord()
                         .iter()
                         .map(|&&s| (true, s)),
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index f15d6fba506..95912b01600 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -18,6 +18,8 @@ codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing
 
 codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto
 
+codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument
+
 codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
 
 codegen_ssa_cgu_not_recorded =
@@ -52,6 +54,10 @@ codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$err
 codegen_ssa_error_writing_def_file =
     Error writing .DEF file: {$error}
 
+codegen_ssa_expected_name_value_pair = expected name value pair
+
+codegen_ssa_expected_one_argument = expected one argument
+
 codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
@@ -88,9 +94,17 @@ codegen_ssa_incorrect_cgu_reuse_type =
 
 codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
 
+codegen_ssa_invalid_argument = invalid argument
+    .help = valid inline arguments are `always` and `never`
+
+codegen_ssa_invalid_instruction_set = invalid instruction set specified
+
 codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
     .note = the attribute requires exactly one argument
 
+codegen_ssa_invalid_literal_value = invalid literal value
+    .label = value must be an integer between `0` and `255`
+
 codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
 
 codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
@@ -217,6 +231,8 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but
 
 codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
 
+codegen_ssa_multiple_instruction_set = cannot specify more than one instruction set
+
 codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
     .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point
 
@@ -229,6 +245,11 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
 
 codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't
 
+codegen_ssa_null_on_export = `export_name` may not contain null characters
+
+codegen_ssa_out_of_range_integer = integer value out of range
+    .label = value must be between `0` and `255`
+
 codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
     .note = {$output}
 
@@ -236,6 +257,8 @@ codegen_ssa_read_file = failed to read file: {$message}
 
 codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
 
+codegen_ssa_requires_rust_abi = `#[track_caller]` requires Rust ABI
+
 codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib at `{$path}`: {$error}
 
 codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
@@ -356,6 +379,9 @@ codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
 
 codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
 
+codegen_ssa_unexpected_parameter_name = unexpected parameter name
+    .label = expected `{$prefix_nops}` or `{$entry_nops}`
+
 codegen_ssa_unknown_archive_kind =
     Don't know how to build archive of type: {$kind}
 
@@ -367,6 +393,8 @@ codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
 
 codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
 
+codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
+
 codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
 
 codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 32f689608f8..3710625ac12 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -63,7 +63,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTr
             },
         };
 
-        for attr in tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) {
+        for attr in tcx.hir_attrs(rustc_hir::CRATE_HIR_ID) {
             ams.check_attr(attr);
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 87992ce2e11..9cc737d194c 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -475,7 +475,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
 ) -> OngoingCodegen<B> {
     let (coordinator_send, coordinator_receive) = channel();
 
-    let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+    let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
     let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
 
     let crate_info = CrateInfo::new(tcx, target_cpu);
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 63f2f8fa3d1..e9c886d28ed 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -876,7 +876,7 @@ impl CrateInfo {
         let linked_symbols =
             crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect();
         let local_crate_name = tcx.crate_name(LOCAL_CRATE);
-        let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+        let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
         let subsystem =
             ast::attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
         let windows_subsystem = subsystem.map(|subsystem| {
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 673740b4aab..998a4ff727e 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -1,15 +1,11 @@
 use std::str::FromStr;
 
 use rustc_abi::ExternAbi;
-use rustc_ast::expand::autodiff_attrs::{
-    AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
-};
+use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
 use rustc_ast::{MetaItem, MetaItemInner, attr};
 use rustc_attr_parsing::ReprAttr::ReprAlign;
 use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::codes::*;
-use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
@@ -64,7 +60,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         );
     }
 
-    let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(did));
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did));
     let mut codegen_fn_attrs = CodegenFnAttrs::new();
     if tcx.should_inherit_track_caller(did) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
@@ -79,7 +75,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
     // When `no_builtins` is applied at the crate level, we should add the
     // `no-builtins` attribute to each function to ensure it takes effect in LTO.
-    let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+    let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
     let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
     if no_builtins {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
@@ -236,13 +232,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     && let Some(fn_sig) = fn_sig()
                     && fn_sig.skip_binder().abi() != ExternAbi::Rust
                 {
-                    struct_span_code_err!(
-                        tcx.dcx(),
-                        attr.span(),
-                        E0737,
-                        "`#[track_caller]` requires Rust ABI"
-                    )
-                    .emit();
+                    tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() });
                 }
                 if is_closure
                     && !tcx.features().closure_track_caller()
@@ -263,13 +253,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     if s.as_str().contains('\0') {
                         // `#[export_name = ...]` will be converted to a null-terminated string,
                         // so it may not contain any null characters.
-                        struct_span_code_err!(
-                            tcx.dcx(),
-                            attr.span(),
-                            E0648,
-                            "`export_name` may not contain null characters"
-                        )
-                        .emit();
+                        tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() });
                     }
                     codegen_fn_attrs.export_name = Some(s);
                     mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
@@ -394,47 +378,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 [sym::arm, sym::a32 | sym::t32]
                                     if !tcx.sess.target.has_thumb_interworking =>
                                 {
-                                    struct_span_code_err!(
-                                        tcx.dcx(),
-                                        attr.span(),
-                                        E0779,
-                                        "target does not support `#[instruction_set]`"
-                                    )
-                                    .emit();
+                                    tcx.dcx().emit_err(errors::UnsuportedInstructionSet {
+                                        span: attr.span(),
+                                    });
                                     None
                                 }
                                 [sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
                                 [sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
                                 _ => {
-                                    struct_span_code_err!(
-                                        tcx.dcx(),
-                                        attr.span(),
-                                        E0779,
-                                        "invalid instruction set specified",
-                                    )
-                                    .emit();
+                                    tcx.dcx().emit_err(errors::InvalidInstructionSet {
+                                        span: attr.span(),
+                                    });
                                     None
                                 }
                             }
                         }
                         [] => {
-                            struct_span_code_err!(
-                                tcx.dcx(),
-                                attr.span(),
-                                E0778,
-                                "`#[instruction_set]` requires an argument"
-                            )
-                            .emit();
+                            tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
                             None
                         }
                         _ => {
-                            struct_span_code_err!(
-                                tcx.dcx(),
-                                attr.span(),
-                                E0779,
-                                "cannot specify more than one instruction set"
-                            )
-                            .emit();
+                            tcx.dcx()
+                                .emit_err(errors::MultipleInstructionSet { span: attr.span() });
                             None
                         }
                     })
@@ -445,58 +410,38 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     let mut entry = None;
                     for item in l {
                         let Some(meta_item) = item.meta_item() else {
-                            tcx.dcx().span_err(item.span(), "expected name value pair");
+                            tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
                             continue;
                         };
 
                         let Some(name_value_lit) = meta_item.name_value_literal() else {
-                            tcx.dcx().span_err(item.span(), "expected name value pair");
+                            tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
                             continue;
                         };
 
-                        fn emit_error_with_label(
-                            tcx: TyCtxt<'_>,
-                            span: Span,
-                            error: impl Into<DiagMessage>,
-                            label: impl Into<SubdiagMessage>,
-                        ) {
-                            let mut err: rustc_errors::Diag<'_, _> =
-                                tcx.dcx().struct_span_err(span, error);
-                            err.span_label(span, label);
-                            err.emit();
-                        }
-
                         let attrib_to_write = match meta_item.name_or_empty() {
                             sym::prefix_nops => &mut prefix,
                             sym::entry_nops => &mut entry,
                             _ => {
-                                emit_error_with_label(
-                                    tcx,
-                                    item.span(),
-                                    "unexpected parameter name",
-                                    format!("expected {} or {}", sym::prefix_nops, sym::entry_nops),
-                                );
+                                tcx.dcx().emit_err(errors::UnexpectedParameterName {
+                                    span: item.span(),
+                                    prefix_nops: sym::prefix_nops,
+                                    entry_nops: sym::entry_nops,
+                                });
                                 continue;
                             }
                         };
 
                         let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
-                            emit_error_with_label(
-                                tcx,
-                                name_value_lit.span,
-                                "invalid literal value",
-                                "value must be an integer between `0` and `255`",
-                            );
+                            tcx.dcx().emit_err(errors::InvalidLiteralValue {
+                                span: name_value_lit.span,
+                            });
                             continue;
                         };
 
                         let Ok(val) = val.get().try_into() else {
-                            emit_error_with_label(
-                                tcx,
-                                name_value_lit.span,
-                                "integer value out of range",
-                                "value must be between `0` and `255`",
-                            );
+                            tcx.dcx()
+                                .emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
                             continue;
                         };
 
@@ -533,7 +478,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         inline_span = Some(attr.span());
 
         let [item] = &items[..] else {
-            struct_span_code_err!(tcx.dcx(), attr.span(), E0534, "expected one argument").emit();
+            tcx.dcx().emit_err(errors::ExpectedOneArgument { span: attr.span() });
             return InlineAttr::None;
         };
 
@@ -542,9 +487,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         } else if item.has_name(sym::never) {
             InlineAttr::Never
         } else {
-            struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument")
-                .with_help("valid inline arguments are `always` and `never`")
-                .emit();
+            tcx.dcx().emit_err(errors::InvalidArgument { span: items[0].span() });
 
             InlineAttr::None
         }
@@ -575,9 +518,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         if !attr.has_name(sym::optimize) {
             return ia;
         }
-        let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit();
         if attr.is_word() {
-            err(attr.span(), "expected one argument");
+            tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
             return ia;
         }
         let Some(ref items) = attr.meta_item_list() else {
@@ -586,7 +528,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
         inline_span = Some(attr.span());
         let [item] = &items[..] else {
-            err(attr.span(), "expected one argument");
+            tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
             return OptimizeAttr::Default;
         };
         if item.has_name(sym::size) {
@@ -596,7 +538,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         } else if item.has_name(sym::none) {
             OptimizeAttr::DoNotOptimize
         } else {
-            err(item.span(), "invalid argument");
+            tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() });
             OptimizeAttr::Default
         }
     });
@@ -930,15 +872,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
         }
     }
 
-    for &input in &arg_activities {
-        if !valid_input_activity(mode, input) {
-            span_bug!(attr.span(), "Invalid input activity {} for {} mode", input, mode);
-        }
-    }
-    if !valid_ret_activity(mode, ret_activity) {
-        span_bug!(attr.span(), "Invalid return activity {} for {} mode", ret_activity, mode);
-    }
-
     Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities })
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index ccf6d12977f..394c80fcfbd 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -136,6 +136,110 @@ pub(crate) struct NoSavedObjectFile<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(codegen_ssa_requires_rust_abi, code = E0737)]
+pub(crate) struct RequiresRustAbi {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_null_on_export, code = E0648)]
+pub(crate) struct NullOnExport {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)]
+pub(crate) struct UnsuportedInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_instruction_set, code = E0779)]
+pub(crate) struct InvalidInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_bare_instruction_set, code = E0778)]
+pub(crate) struct BareInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_multiple_instruction_set, code = E0779)]
+pub(crate) struct MultipleInstructionSet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_name_value_pair)]
+pub(crate) struct ExpectedNameValuePair {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unexpected_parameter_name)]
+pub(crate) struct UnexpectedParameterName {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub prefix_nops: Symbol,
+    pub entry_nops: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_literal_value)]
+pub(crate) struct InvalidLiteralValue {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_out_of_range_integer)]
+pub(crate) struct OutOfRangeInteger {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_one_argument, code = E0534)]
+pub(crate) struct ExpectedOneArgument {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_expected_one_argument, code = E0722)]
+pub(crate) struct ExpectedOneArgumentOptimize {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_argument, code = E0535)]
+#[help]
+pub(crate) struct InvalidArgument {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_argument, code = E0722)]
+pub(crate) struct InvalidArgumentOptimize {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(codegen_ssa_copy_path_buf)]
 pub(crate) struct CopyPathBuf {
     pub source_file: PathBuf,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 95a5e96fe46..8058cd1b178 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -190,7 +190,7 @@ pub(crate) fn provide(providers: &mut Providers) {
         },
         implied_target_features: |tcx, feature: Symbol| {
             let feature = feature.as_str();
-            UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
+            UnordSet::from(tcx.sess.target.implied_target_features(feature))
                 .into_sorted_stable_ord()
                 .into_iter()
                 .map(|s| Symbol::intern(s))
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index ebcf118b903..65fd843e7a5 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -45,10 +45,13 @@ pub trait CodegenBackend {
 
     fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
 
-    /// Returns the features that should be set in `cfg(target_features)`.
+    /// Returns two feature sets:
+    /// - The first has the features that should be set in `cfg(target_features)`.
+    /// - The second is like the first, but also includes unstable features.
+    ///
     /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
-    fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
-        vec![]
+    fn target_features_cfg(&self, _sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
+        (vec![], vec![])
     }
 
     fn print_passes(&self) {}
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 607cb2e497d..06ee7075170 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -81,7 +81,7 @@ pub fn rustc_allow_const_fn_unstable(
     def_id: LocalDefId,
     feature_gate: Symbol,
 ) -> bool {
-    let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id));
+    let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
 
     find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate))
 }
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index ce0b5a350e0..e5af0673629 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -982,6 +982,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     todo.push(id);
                 }
             }
+            // Also expose the provenance of the interpreter-level allocation, so it can
+            // be read by FFI. The `black_box` is defensive programming as LLVM likes
+            // to (incorrectly) optimize away ptr2int casts whose result is unused.
+            std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance());
 
             // Prepare for possible write from native code if mutable.
             if info.mutbl.is_mut() {
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 8d19fc5f9cc..f63b201742d 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -315,6 +315,7 @@ mod helper {
     use super::*;
     pub(super) type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;
     impl<O: ForestObligation> ObligationForest<O> {
+        #[cfg_attr(not(bootstrap), define_opaque(ObligationTreeIdGenerator))]
         pub fn new() -> ObligationForest<O> {
             ObligationForest {
                 nodes: vec![],
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 828a14e707c..16d70af7e05 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -268,8 +268,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
             let tcx = ex.tcx();
             let f = |annotation: &dyn pprust_hir::PpAnn| {
                 let sm = sess.source_map();
-                let hir_map = tcx.hir();
-                let attrs = |id| hir_map.attrs(id);
+                let attrs = |id| tcx.hir_attrs(id);
                 pprust_hir::print_crate(
                     sm,
                     tcx.hir_root_module(),
diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md
index 5e3dcc4aa72..033e1c65192 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0792.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0792.md
@@ -7,6 +7,7 @@ This means
 
 type Foo<T> = impl std::fmt::Debug;
 
+#[define_opaque(Foo)]
 fn foo() -> Foo<u32> {
     5u32
 }
@@ -19,6 +20,7 @@ is not accepted. If it were accepted, one could create unsound situations like
 
 type Foo<T> = impl Default;
 
+#[define_opaque(Foo)]
 fn foo() -> Foo<u32> {
     5u32
 }
@@ -36,6 +38,7 @@ Instead you need to make the function generic:
 
 type Foo<T> = impl std::fmt::Debug;
 
+#[define_opaque(Foo)]
 fn foo<U>() -> Foo<U> {
     5u32
 }
@@ -56,6 +59,7 @@ use std::fmt::Debug;
 
 type Foo<T: Debug> = impl Debug;
 
+#[define_opaque(Foo)]
 fn foo<U: Debug>() -> Foo<U> {
     Vec::<U>::new()
 }
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a6fbbb29ccd..066546ecf74 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -208,6 +208,7 @@ pub type LazyFallbackBundle = Arc<LazyLock<FluentBundle, impl FnOnce() -> Fluent
 
 /// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
 #[instrument(level = "trace", skip(resources))]
+#[cfg_attr(not(bootstrap), define_opaque(LazyFallbackBundle))]
 pub fn fallback_fluent_bundle(
     resources: Vec<&'static str>,
     with_directionality_markers: bool,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c523bcece72..87f01be26c2 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -780,8 +780,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             }
                         }
                         Err(err) => {
-                            let guar = err.emit();
-                            fragment_kind.dummy(span, guar)
+                            let _guar = err.emit();
+                            fragment_kind.expect_from_annotatables(iter::once(item))
                         }
                     }
                 }
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 8cb001391c5..0ea53627fe7 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -274,7 +274,7 @@ fn parse_tree<'a>(
                     let msg =
                         format!("expected identifier, found `{}`", pprust::token_to_string(token),);
                     sess.dcx().span_err(token.span, msg);
-                    TokenTree::MetaVar(token.span, Ident::empty())
+                    TokenTree::MetaVar(token.span, Ident::dummy())
                 }
 
                 // There are no more tokens. Just return the `$` we already have.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 7741f6668c3..3c61bfd1c93 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -240,7 +240,7 @@ declare_features! (
     /// Added for testing unstable lints; perma-unstable.
     (internal, test_unstable_lint, "1.60.0", None),
     /// Helps with formatting for `group_imports = "StdExternalCrate"`.
-    (unstable, unqualified_local_imports, "1.83.0", None),
+    (unstable, unqualified_local_imports, "1.83.0", Some(138299)),
     /// Use for stable + negative coherence and strict coherence depending on trait's
     /// rustc_strict_coherence value.
     (unstable, with_negative_coherence, "1.60.0", None),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 928455ace85..d4dfb9f2973 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -243,7 +243,7 @@ impl<'hir> PathSegment<'hir> {
     }
 
     pub fn invalid() -> Self {
-        Self::new(Ident::empty(), HirId::INVALID, Res::Err)
+        Self::new(Ident::dummy(), HirId::INVALID, Res::Err)
     }
 
     pub fn args(&self) -> &GenericArgs<'hir> {
@@ -1307,13 +1307,18 @@ impl Attribute {
 #[derive(Debug)]
 pub struct AttributeMap<'tcx> {
     pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
+    /// Preprocessed `#[define_opaque]` attribute.
+    pub define_opaque: Option<&'tcx [(Span, LocalDefId)]>,
     // Only present when the crate hash is needed.
     pub opt_hash: Option<Fingerprint>,
 }
 
 impl<'tcx> AttributeMap<'tcx> {
-    pub const EMPTY: &'static AttributeMap<'static> =
-        &AttributeMap { map: SortedMap::new(), opt_hash: Some(Fingerprint::ZERO) };
+    pub const EMPTY: &'static AttributeMap<'static> = &AttributeMap {
+        map: SortedMap::new(),
+        opt_hash: Some(Fingerprint::ZERO),
+        define_opaque: None,
+    };
 
     #[inline]
     pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
@@ -4327,16 +4332,6 @@ pub enum OwnerNode<'hir> {
 }
 
 impl<'hir> OwnerNode<'hir> {
-    pub fn ident(&self) -> Option<Ident> {
-        match self {
-            OwnerNode::Item(Item { ident, .. })
-            | OwnerNode::ForeignItem(ForeignItem { ident, .. })
-            | OwnerNode::ImplItem(ImplItem { ident, .. })
-            | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident),
-            OwnerNode::Crate(..) | OwnerNode::Synthetic => None,
-        }
-    }
-
     pub fn span(&self) -> Span {
         match self {
             OwnerNode::Item(Item { span, .. })
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 25d2a825343..3ef645a5f61 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -363,7 +363,7 @@ pub trait Visitor<'v>: Sized {
     /// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
     /// ambiguous.
     ///
-    /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
+    /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
     fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
         walk_ty(self, t)
     }
@@ -374,7 +374,7 @@ pub trait Visitor<'v>: Sized {
     /// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
     /// ambiguous.
     ///
-    /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars.
+    /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
     fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
         walk_ambig_const_arg(self, c)
     }
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 2709a826549..91ea88cae47 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -106,7 +106,7 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         // We ignore the `map` since it refers to information included in `opt_hash` which is
         // hashed in the collector and used for the crate hash.
-        let AttributeMap { opt_hash, map: _ } = *self;
+        let AttributeMap { opt_hash, define_opaque: _, map: _ } = *self;
         opt_hash.unwrap().hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 935f4de6c58..194f2cd04e4 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -504,12 +504,9 @@ hir_analysis_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by
 
 hir_analysis_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait
 
-hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
-    .note = this item must mention the opaque type in its signature in order to be able to register hidden types
-
-hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, but has it in its signature
-    .note = consider moving the opaque type's declaration and defining uses into a separate module
-    .opaque = this opaque type is in the signature
+hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`
+    .note = consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`
+    .opaque = this opaque type is supposed to be constrained
 
 hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 8f9997cb62c..a266286664c 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -185,7 +185,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
 /// projections that would result in "inheriting lifetimes".
 fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let hir::OpaqueTy { origin, .. } = *tcx.hir().expect_opaque_ty(def_id);
+    let hir::OpaqueTy { origin, .. } = *tcx.hir_expect_opaque_ty(def_id);
 
     // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
     // `async-std` (and `pub async fn` in general).
@@ -392,6 +392,12 @@ fn best_definition_site_of_opaque<'tcx>(
                 return ControlFlow::Continue(());
             }
 
+            let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+            // Don't try to check items that cannot possibly constrain the type.
+            if !opaque_types_defined_by.contains(&self.opaque_def_id) {
+                return ControlFlow::Continue(());
+            }
+
             if let Some(hidden_ty) =
                 self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
             {
@@ -451,19 +457,7 @@ fn best_definition_site_of_opaque<'tcx>(
             None
         }
         hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
-            let scope = tcx.hir_get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
-            let found = if scope == hir::CRATE_HIR_ID {
-                tcx.hir_walk_toplevel_module(&mut locator)
-            } else {
-                match tcx.hir_node(scope) {
-                    Node::Item(it) => locator.visit_item(it),
-                    Node::ImplItem(it) => locator.visit_impl_item(it),
-                    Node::TraitItem(it) => locator.visit_trait_item(it),
-                    Node::ForeignItem(it) => locator.visit_foreign_item(it),
-                    other => bug!("{:?} is not a valid scope for an opaque type item", other),
-                }
-            };
-            found.break_value()
+            tcx.hir_walk_toplevel_module(&mut locator).break_value()
         }
     }
 }
@@ -791,7 +785,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             check_type_alias_type_params_are_used(tcx, def_id);
         }
         DefKind::ForeignMod => {
-            let it = tcx.hir().expect_item(def_id);
+            let it = tcx.hir_expect_item(def_id);
             let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
                 return;
             };
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index c193aad2afd..0a37a27b35b 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1031,7 +1031,7 @@ fn report_trait_method_mismatch<'tcx>(
             // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
             // span points only at the type `Box<Self`>, but we want to cover the whole
             // argument pattern and type.
-            let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
+            let (sig, body) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
             let span = tcx
                 .hir_body_param_names(body)
                 .zip(sig.decl.inputs.iter())
@@ -1051,7 +1051,7 @@ fn report_trait_method_mismatch<'tcx>(
                 // Suggestion to change output type. We do not suggest in `async` functions
                 // to avoid complex logic or incorrect output.
                 if let ImplItemKind::Fn(sig, _) =
-                    &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind
+                    &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).kind
                     && !sig.header.asyncness.is_async()
                 {
                     let msg = "change the output type to match the trait";
@@ -1190,12 +1190,12 @@ fn extract_spans_for_error_reporting<'tcx>(
 ) -> (Span, Option<Span>) {
     let tcx = infcx.tcx;
     let mut impl_args = {
-        let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
+        let (sig, _) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
         sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
     };
 
     let trait_args = trait_m.def_id.as_local().map(|def_id| {
-        let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn();
+        let (sig, _) = tcx.hir_expect_trait_item(def_id).expect_fn();
         sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
     });
 
@@ -1371,7 +1371,7 @@ fn compare_number_of_generics<'tcx>(
                 spans
             };
             let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
-                let trait_item = tcx.hir().expect_trait_item(def_id);
+                let trait_item = tcx.hir_expect_trait_item(def_id);
                 let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
                 let impl_trait_spans: Vec<Span> = trait_item
                     .generics
@@ -1388,7 +1388,7 @@ fn compare_number_of_generics<'tcx>(
                 (trait_span.map(|s| vec![s]), vec![])
             };
 
-            let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
+            let impl_item = tcx.hir_expect_impl_item(impl_.def_id.expect_local());
             let impl_item_impl_trait_spans: Vec<Span> = impl_item
                 .generics
                 .params
@@ -1466,7 +1466,7 @@ fn compare_number_of_method_arguments<'tcx>(
             .def_id
             .as_local()
             .and_then(|def_id| {
-                let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn();
+                let (trait_m_sig, _) = &tcx.hir_expect_trait_item(def_id).expect_fn();
                 let pos = trait_number_args.saturating_sub(1);
                 trait_m_sig.decl.inputs.get(pos).map(|arg| {
                     if pos == 0 {
@@ -1478,7 +1478,7 @@ fn compare_number_of_method_arguments<'tcx>(
             })
             .or_else(|| tcx.hir().span_if_local(trait_m.def_id));
 
-        let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
+        let (impl_m_sig, _) = &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
         let pos = impl_number_args.saturating_sub(1);
         let impl_span = impl_m_sig
             .decl
@@ -1580,10 +1580,10 @@ fn compare_synthetic_generics<'tcx>(
                     // as another generic argument
                     let new_name = tcx.opt_item_name(trait_def_id)?;
                     let trait_m = trait_m.def_id.as_local()?;
-                    let trait_m = tcx.hir().expect_trait_item(trait_m);
+                    let trait_m = tcx.hir_expect_trait_item(trait_m);
 
                     let impl_m = impl_m.def_id.as_local()?;
-                    let impl_m = tcx.hir().expect_impl_item(impl_m);
+                    let impl_m = tcx.hir_expect_impl_item(impl_m);
 
                     // in case there are no generics, take the spot between the function name
                     // and the opening paren of the argument list
@@ -1613,7 +1613,7 @@ fn compare_synthetic_generics<'tcx>(
                 err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
                 let _: Option<_> = try {
                     let impl_m = impl_m.def_id.as_local()?;
-                    let impl_m = tcx.hir().expect_impl_item(impl_m);
+                    let impl_m = tcx.hir_expect_impl_item(impl_m);
                     let (sig, _) = impl_m.expect_fn();
                     let input_tys = sig.decl.inputs;
 
@@ -1855,7 +1855,7 @@ fn compare_const_predicate_entailment<'tcx>(
         debug!(?impl_ty, ?trait_ty);
 
         // Locate the Span containing just the type of the offending impl
-        let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const();
+        let (ty, _) = tcx.hir_expect_impl_item(impl_ct_def_id).expect_const();
         cause.span = ty.span;
 
         let mut diag = struct_span_code_err!(
@@ -1868,7 +1868,7 @@ fn compare_const_predicate_entailment<'tcx>(
 
         let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
             // Add a label to the Span containing just the type of the const
-            let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const();
+            let (ty, _) = tcx.hir_expect_trait_item(trait_ct_def_id).expect_const();
             ty.span
         });
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a400aaa8142..fd5ffdc2d7a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -513,7 +513,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
             continue;
         }
 
-        let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
+        let gat_item_hir = tcx.hir_expect_trait_item(gat_def_id);
         debug!(?required_bounds);
         let param_env = tcx.param_env(gat_def_id);
 
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 750c09887a1..464ffa8711a 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -31,7 +31,7 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) {
         if used_trait_imports.contains(&id) {
             continue;
         }
-        let item = tcx.hir().expect_item(id);
+        let item = tcx.hir_expect_item(id);
         if item.span.is_dummy() {
             continue;
         }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index cee2f487639..c918abe4c07 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -82,7 +82,7 @@ fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaran
         _ => {}
     }
 
-    let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
+    let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
 
     Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
 }
@@ -109,7 +109,7 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
     match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
         Ok(()) => Ok(()),
         Err(CopyImplementationError::InfringingFields(fields)) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(infringing_fields_error(
                 tcx,
                 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
@@ -119,15 +119,15 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
             ))
         }
         Err(CopyImplementationError::NotAnAdt) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
         }
         Err(CopyImplementationError::HasDestructor) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
         }
         Err(CopyImplementationError::HasUnsafeFields) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx
                 .dcx()
                 .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
@@ -157,7 +157,7 @@ fn visit_implementation_of_const_param_ty(
     match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) {
         Ok(()) => Ok(()),
         Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(infringing_fields_error(
                 tcx,
                 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
@@ -167,11 +167,11 @@ fn visit_implementation_of_const_param_ty(
             ))
         }
         Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
         }
         Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(infringing_fields_error(
                 tcx,
                 infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
@@ -181,7 +181,7 @@ fn visit_implementation_of_const_param_ty(
             ))
         }
         Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
-            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
         }
     }
@@ -526,7 +526,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
                     note: true,
                 }));
             } else if diff_fields.len() > 1 {
-                let item = tcx.hir().expect_item(impl_did);
+                let item = tcx.hir_expect_item(impl_did);
                 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
                     t.path.span
                 } else {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index dbf7a7378f5..0b7fc44460e 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -376,7 +376,7 @@ fn emit_orphan_check_error<'tcx>(
 ) -> ErrorGuaranteed {
     match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
-            let item = tcx.hir().expect_item(impl_def_id);
+            let item = tcx.hir_expect_item(impl_def_id);
             let impl_ = item.expect_impl();
             let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 49523912b14..cfb6cf8a287 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -469,8 +469,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                 hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
                     let item = self
                         .tcx
-                        .hir()
-                        .expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id);
+                        .hir_expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id);
                     match &item.kind {
                         hir::ItemKind::Enum(_, generics)
                         | hir::ItemKind::Struct(_, generics)
@@ -1143,7 +1142,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
 }
 
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
-    let item = tcx.hir().expect_item(def_id);
+    let item = tcx.hir_expect_item(def_id);
 
     let (is_alias, is_auto, safety, items) = match item.kind {
         hir::ItemKind::Trait(is_auto, safety, .., items) => {
@@ -1342,7 +1341,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
         ),
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => {
-            let abi = tcx.hir().get_foreign_abi(hir_id);
+            let abi = tcx.hir_get_foreign_abi(hir_id);
             compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety())
         }
 
@@ -1597,7 +1596,7 @@ pub fn suggest_impl_trait<'tcx>(
 
 fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTraitHeader<'_>> {
     let icx = ItemCtxt::new(tcx, def_id);
-    let item = tcx.hir().expect_item(def_id);
+    let item = tcx.hir_expect_item(def_id);
     let impl_ = item.expect_impl();
     impl_.of_trait.as_ref().map(|ast_trait_ref| {
         let selfty = tcx.type_of(def_id).instantiate_identity();
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 4debd3977f5..7cbd31de6ba 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -13,7 +13,7 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
     for id in tcx.hir_crate_items(()).opaques() {
         if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
         | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } =
-            tcx.hir().expect_opaque_ty(id).origin
+            tcx.hir_expect_opaque_ty(id).origin
             && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
             && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
         {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 6936544838c..16caa4f6874 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -480,5 +480,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
             }
         }
     }
-    HasTait.visit_ty_unambig(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
+    HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().0).is_break()
 }
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 399c4fbe55a..142078900f0 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,14 +1,13 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def};
+use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::DUMMY_SP;
 use tracing::{debug, instrument, trace};
 
-use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType};
+use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
 
 /// Checks "defining uses" of opaque `impl Trait` in associated types.
 /// These can only be defined by associated items of the same trait.
@@ -82,38 +81,9 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
 /// ```
 #[instrument(skip(tcx), level = "debug")]
 pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
-    let hir_id = tcx.local_def_id_to_hir_id(def_id);
-    let scope = tcx.hir_get_defining_scope(hir_id);
     let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
 
-    debug!(?scope);
-
-    if scope == hir::CRATE_HIR_ID {
-        tcx.hir_walk_toplevel_module(&mut locator);
-    } else {
-        trace!("scope={:#?}", tcx.hir_node(scope));
-        match tcx.hir_node(scope) {
-            // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
-            // This allows our visitor to process the defining item itself, causing
-            // it to pick up any 'sibling' defining uses.
-            //
-            // For example, this code:
-            // ```
-            // fn foo() {
-            //     type Blah = impl Debug;
-            //     let my_closure = || -> Blah { true };
-            // }
-            // ```
-            //
-            // requires us to explicitly process `foo()` in order
-            // to notice the defining usage of `Blah`.
-            Node::Item(it) => locator.visit_item(it),
-            Node::ImplItem(it) => locator.visit_impl_item(it),
-            Node::TraitItem(it) => locator.visit_trait_item(it),
-            Node::ForeignItem(it) => locator.visit_foreign_item(it),
-            other => bug!("{:?} is not a valid scope for an opaque type item", other),
-        }
-    }
+    tcx.hir_walk_toplevel_module(&mut locator);
 
     if let Some(hidden) = locator.found {
         // Only check against typeck if we didn't already error
@@ -137,12 +107,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
         let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
             name: tcx.item_ident(parent_def_id.to_def_id()),
-            what: match tcx.hir_node(scope) {
-                _ if scope == hir::CRATE_HIR_ID => "module",
-                Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
-                Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
-                _ => "item",
-            },
+            what: "crate",
         });
         Ty::new_error(tcx, reported)
     }
@@ -176,6 +141,13 @@ impl TaitConstraintLocator<'_> {
             return;
         }
 
+        let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+        // Don't try to check items that cannot possibly constrain the type.
+        if !opaque_types_defined_by.contains(&self.def_id) {
+            debug!("no constraint: no opaque types defined");
+            return;
+        }
+
         // Function items with `_` in their return type already emit an error, skip any
         // "non-defining use" errors for them.
         // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
@@ -215,8 +187,6 @@ impl TaitConstraintLocator<'_> {
             return;
         }
 
-        let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
-
         let mut constrained = false;
         for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
             if opaque_type_key.def_id != self.def_id {
@@ -224,20 +194,6 @@ impl TaitConstraintLocator<'_> {
             }
             constrained = true;
 
-            if !opaque_types_defined_by.contains(&self.def_id) {
-                let guar = self.tcx.dcx().emit_err(TaitForwardCompat {
-                    span: hidden_type.span,
-                    item_span: self
-                        .tcx
-                        .def_ident_span(item_def_id)
-                        .unwrap_or_else(|| self.tcx.def_span(item_def_id)),
-                });
-                // Avoid "opaque type not constrained" errors on the opaque itself.
-                self.found = Some(ty::OpaqueHiddenType {
-                    span: DUMMY_SP,
-                    ty: Ty::new_error(self.tcx, guar),
-                });
-            }
             let concrete_type =
                 self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
                     opaque_type_key,
@@ -309,19 +265,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
     }
     fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
         trace!(?it.owner_id);
-        // The opaque type itself or its children are not within its reveal scope.
-        if it.owner_id.def_id != self.def_id {
-            self.check(it.owner_id.def_id);
-            intravisit::walk_item(self, it);
-        }
+        self.check(it.owner_id.def_id);
+        intravisit::walk_item(self, it);
     }
     fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
         trace!(?it.owner_id);
-        // The opaque type itself or its children are not within its reveal scope.
-        if it.owner_id.def_id != self.def_id {
-            self.check(it.owner_id.def_id);
-            intravisit::walk_impl_item(self, it);
-        }
+        self.check(it.owner_id.def_id);
+        intravisit::walk_impl_item(self, it);
     }
     fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
         trace!(?it.owner_id);
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 4dbdfa3d85a..cb711ebb91a 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -404,7 +404,7 @@ fn check_constraints<'tcx>(
     };
 
     if let Some(local_sig_id) = sig_id.as_local()
-        && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some()
+        && tcx.hir_opt_delegation_sig_id(local_sig_id).is_some()
     {
         emit("recursive delegation is not supported yet");
     }
@@ -416,7 +416,7 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
 ) -> &'tcx [Ty<'tcx>] {
-    let sig_id = tcx.hir().opt_delegation_sig_id(def_id).unwrap();
+    let sig_id = tcx.hir_opt_delegation_sig_id(def_id).unwrap();
     let caller_sig = tcx.fn_sig(sig_id);
     if let Err(err) = check_constraints(tcx, def_id, sig_id) {
         let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1;
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 4c6c2504126..f2560f22874 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -425,16 +425,6 @@ pub(crate) struct UnconstrainedOpaqueType {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_tait_forward_compat)]
-#[note]
-pub(crate) struct TaitForwardCompat {
-    #[primary_span]
-    pub span: Span,
-    #[note]
-    pub item_span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_tait_forward_compat2)]
 #[note]
 pub(crate) struct TaitForwardCompat2 {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index ace5e34b382..fa061c80618 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1520,7 +1520,7 @@ fn generics_args_err_extend<'a>(
                 })
                 .collect();
             if args.len() > 1
-                && let Some(span) = args.into_iter().last()
+                && let Some(span) = args.into_iter().next_back()
             {
                 err.note(
                     "generic arguments are not allowed on both an enum and its variant's path \
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 3611db7c68f..e78801dd601 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -78,13 +78,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
 
         if self_ty.span.edition().at_least_rust_2021() {
-            let msg = "expected a type, found a trait";
-            let label = "you can add the `dyn` keyword if you want a trait object";
-            let mut diag =
-                rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
+            let mut diag = rustc_errors::struct_span_code_err!(
+                self.dcx(),
+                self_ty.span,
+                E0782,
+                "{}",
+                "expected a type, found a trait"
+            );
             if self_ty.span.can_be_used_for_suggestions()
                 && !self.maybe_suggest_impl_trait(self_ty, &mut diag)
-                && !self.maybe_suggest_dyn_trait(self_ty, label, sugg, &mut diag)
+                && !self.maybe_suggest_dyn_trait(self_ty, sugg, &mut diag)
             {
                 self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag);
             }
@@ -123,31 +126,62 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
+    /// For a struct or enum with an invalid bare trait object field, suggest turning
+    /// it into a generic type bound.
     fn maybe_suggest_add_generic_impl_trait(
         &self,
         self_ty: &hir::Ty<'_>,
         diag: &mut Diag<'_>,
     ) -> bool {
         let tcx = self.tcx();
-        let msg = "you might be missing a type parameter";
-        let mut sugg = vec![];
 
-        let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
-        let parent_item = tcx.hir_node_by_def_id(parent_id).expect_item();
-        match parent_item.kind {
-            hir::ItemKind::Struct(_, generics) | hir::ItemKind::Enum(_, generics) => {
-                sugg.push((
-                    generics.where_clause_span,
-                    format!(
-                        "<T: {}>",
-                        self.tcx().sess.source_map().span_to_snippet(self_ty.span).unwrap()
-                    ),
-                ));
-                sugg.push((self_ty.span, "T".to_string()));
+        let parent_hir_id = tcx.parent_hir_id(self_ty.hir_id);
+        let parent_item = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
+
+        let generics = match tcx.hir_node_by_def_id(parent_item) {
+            hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Struct(variant, generics), ..
+            }) => {
+                if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
+                    return false;
+                }
+                generics
             }
-            _ => {}
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(def, generics), .. }) => {
+                if !def
+                    .variants
+                    .iter()
+                    .flat_map(|variant| variant.data.fields().iter())
+                    .any(|field| field.hir_id == parent_hir_id)
+                {
+                    return false;
+                }
+                generics
+            }
+            _ => return false,
+        };
+
+        let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
+            return false;
+        };
+
+        let param = "TUV"
+            .chars()
+            .map(|c| c.to_string())
+            .chain((0..).map(|i| format!("P{i}")))
+            .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
+            .expect("we definitely can find at least one param name to generate");
+        let mut sugg = vec![(self_ty.span, param.to_string())];
+        if let Some(insertion_span) = generics.span_for_param_suggestion() {
+            sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
+        } else {
+            sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
         }
-        diag.multipart_suggestion_verbose(msg, sugg, Applicability::MachineApplicable);
+        diag.multipart_suggestion_verbose(
+            "you might be missing a type parameter",
+            sugg,
+            Applicability::MachineApplicable,
+        );
         true
     }
     /// Make sure that we are in the condition to suggest the blanket implementation.
@@ -198,32 +232,59 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
+    /// Try our best to approximate when adding `dyn` would be helpful for a bare
+    /// trait object.
+    ///
+    /// Right now, this is if the type is either directly nested in another ty,
+    /// or if it's in the tail field within a struct. This approximates what the
+    /// user would've gotten on edition 2015, except for the case where we have
+    /// an *obvious* knock-on `Sized` error.
     fn maybe_suggest_dyn_trait(
         &self,
         self_ty: &hir::Ty<'_>,
-        label: &str,
         sugg: Vec<(Span, String)>,
         diag: &mut Diag<'_>,
     ) -> bool {
         let tcx = self.tcx();
-        let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
-        let parent_item = tcx.hir_node_by_def_id(parent_id).expect_item();
 
-        // If the parent item is an enum, don't suggest the dyn trait.
-        if let hir::ItemKind::Enum(..) = parent_item.kind {
-            return false;
-        }
+        // Look at the direct HIR parent, since we care about the relationship between
+        // the type and the thing that directly encloses it.
+        match tcx.parent_hir_node(self_ty.hir_id) {
+            // These are all generally ok. Namely, when a trait object is nested
+            // into another expression or ty, it's either very certain that they
+            // missed the ty (e.g. `&Trait`) or it's not really possible to tell
+            // what their intention is, so let's not give confusing suggestions and
+            // just mention `dyn`. The user can make up their mind what to do here.
+            hir::Node::Ty(_)
+            | hir::Node::Expr(_)
+            | hir::Node::PatExpr(_)
+            | hir::Node::PathSegment(_)
+            | hir::Node::AssocItemConstraint(_)
+            | hir::Node::TraitRef(_)
+            | hir::Node::Item(_)
+            | hir::Node::WherePredicate(_) => {}
 
-        // If the parent item is a struct, check if self_ty is the last field.
-        if let hir::ItemKind::Struct(variant_data, _) = parent_item.kind {
-            if variant_data.fields().last().unwrap().ty.span != self_ty.span {
-                return false;
+            hir::Node::Field(field) => {
+                // Enums can't have unsized fields, fields can only have an unsized tail field.
+                if let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Struct(variant, _), ..
+                }) = tcx.parent_hir_node(field.hir_id)
+                    && variant
+                        .fields()
+                        .last()
+                        .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
+                {
+                    // Ok
+                } else {
+                    return false;
+                }
             }
+            _ => return false,
         }
 
         // FIXME: Only emit this suggestion if the trait is dyn-compatible.
         diag.multipart_suggestion_verbose(
-            label.to_string(),
+            "you can add the `dyn` keyword if you want a trait object",
             sugg,
             Applicability::MachineApplicable,
         );
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index dd6c40bfbb8..8fff6eb9f6e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -370,7 +370,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     #[instrument(level = "debug", skip(self), ret)]
     pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> {
         let tcx = self.tcx();
-        let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id));
+        let lifetime_name = |def_id| tcx.hir_name(tcx.local_def_id_to_hir_id(def_id));
 
         match resolved {
             rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static,
@@ -2294,18 +2294,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         {
             let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args);
 
-            // We must error if the instantiated type has any inference variables as we will
-            // use this type to feed the `type_of` and query results must not contain inference
-            // variables otherwise we will ICE.
-            //
+            // FIXME(generic_const_parameter_types): Ideally we remove these errors below when
+            // we have the ability to intermix typeck of anon const const args with the parent
+            // bodies typeck.
+
             // We also error if the type contains any regions as effectively any region will wind
             // up as a region variable in mir borrowck. It would also be somewhat concerning if
             // hir typeck was using equality but mir borrowck wound up using subtyping as that could
             // result in a non-infer in hir typeck but a region variable in borrowck.
-            //
-            // FIXME(generic_const_parameter_types): Ideally we remove these errors one day when
-            // we have the ability to intermix typeck of anon const const args with the parent
-            // bodies typeck.
             if tcx.features().generic_const_parameter_types()
                 && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
             {
@@ -2316,6 +2312,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
                 return ty::Const::new_error(tcx, e);
             }
+            // We must error if the instantiated type has any inference variables as we will
+            // use this type to feed the `type_of` and query results must not contain inference
+            // variables otherwise we will ICE.
             if anon_const_type.has_non_region_infer() {
                 let e = tcx.dcx().span_err(
                     const_arg.span(),
@@ -2324,6 +2323,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
                 return ty::Const::new_error(tcx, e);
             }
+            // We error when the type contains unsubstituted generics since we do not currently
+            // give the anon const any of the generics from the parent.
+            if anon_const_type.has_non_region_param() {
+                let e = tcx.dcx().span_err(
+                    const_arg.span(),
+                    "anonymous constants referencing generics are not yet supported",
+                );
+                tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e)));
+                return ty::Const::new_error(tcx, e);
+            }
 
             tcx.feed_anon_const_type(
                 anon.def_id,
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 0e3721126fb..3067766fb4d 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -117,9 +117,9 @@ impl<'a> State<'a> {
                 self.hardbreak()
             }
             hir::Attribute::Parsed(pa) => {
-                self.word("#[attr=\"");
+                self.word("#[attr = ");
                 pa.print_attribute(self);
-                self.word("\")]");
+                self.word("]");
                 self.hardbreak()
             }
         }
@@ -552,24 +552,6 @@ impl<'a> State<'a> {
         self.word(";")
     }
 
-    fn print_item_type(
-        &mut self,
-        item: &hir::Item<'_>,
-        generics: &hir::Generics<'_>,
-        inner: impl Fn(&mut Self),
-    ) {
-        self.head("type");
-        self.print_ident(item.ident);
-        self.print_generic_params(generics.params);
-        self.end(); // end the inner ibox
-
-        self.print_where_clause(generics);
-        self.space();
-        inner(self);
-        self.word(";");
-        self.end(); // end the outer ibox
-    }
-
     fn print_item(&mut self, item: &hir::Item<'_>) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
@@ -682,10 +664,17 @@ impl<'a> State<'a> {
                 self.end()
             }
             hir::ItemKind::TyAlias(ty, generics) => {
-                self.print_item_type(item, generics, |state| {
-                    state.word_space("=");
-                    state.print_type(ty);
-                });
+                self.head("type");
+                self.print_ident(item.ident);
+                self.print_generic_params(generics.params);
+                self.end(); // end the inner ibox
+
+                self.print_where_clause(generics);
+                self.space();
+                self.word_space("=");
+                self.print_type(ty);
+                self.word(";");
+                self.end(); // end the outer ibox
             }
             hir::ItemKind::Enum(ref enum_definition, params) => {
                 self.print_enum_def(enum_definition, params, item.ident.name, item.span);
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 5e00161f693..2a24d626ac3 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -799,7 +799,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // Emit a different diagnostic for local variables, as they are not
                         // type definitions themselves, but rather variables *of* that type.
                         Res::Local(hir_id) => {
-                            err.arg("local_name", self.tcx.hir().name(hir_id));
+                            err.arg("local_name", self.tcx.hir_name(hir_id));
                             Some(fluent_generated::hir_typeck_invalid_local)
                         }
                         Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 786e8b876a6..7c6bb495be3 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -298,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Combine the diverging and has_error flags.
         self.diverges.set(self.diverges.get() | old_diverges);
 
-        debug!("type of {} is...", self.tcx.hir().node_to_string(expr.hir_id));
+        debug!("type of {} is...", self.tcx.hir_id_to_string(expr.hir_id));
         debug!("... {:?}, expected is {:?}", ty, expected);
 
         ty
@@ -2933,7 +2933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let guar = if field.name == kw::Empty {
-            self.dcx().span_delayed_bug(field.span, "field name with no name")
+            self.dcx().span_bug(field.span, "field name with no name")
         } else if self.method_exists_for_diagnostic(
             field,
             base_ty,
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 9ff7eeb2368..63e4a8fb44b 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -1235,7 +1235,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 self.cx.tainted_by_errors()?;
                 bug!(
                     "no type for node {} in mem_categorization",
-                    self.cx.tcx().hir().node_to_string(id)
+                    self.cx.tcx().hir_id_to_string(id)
                 );
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index c46a42c5de1..c82f7a91168 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -140,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub(crate) fn local_ty(&self, span: Span, nid: HirId) -> Ty<'tcx> {
         self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
-            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
+            span_bug!(span, "no type for local variable {}", self.tcx.hir_id_to_string(nid))
         })
     }
 
@@ -220,6 +220,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         debug!("fcx {}", self.tag());
 
+        // Don't write user type annotations for const param types, since we give them
+        // identity args just so that we can trivially substitute their `EarlyBinder`.
+        // We enforce that they match their type in MIR later on.
+        if matches!(self.tcx.def_kind(def_id), DefKind::ConstParam) {
+            return;
+        }
+
         if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) {
             let canonicalized = self.canonicalize_user_type_annotation(ty::UserType::new(
                 ty::UserTypeKind::TypeOf(def_id, UserArgs { args, user_self_ty }),
@@ -552,11 +559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Some(&t) => t,
             None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e),
             None => {
-                bug!(
-                    "no type for node {} in fcx {}",
-                    self.tcx.hir().node_to_string(id),
-                    self.tag()
-                );
+                bug!("no type for node {} in fcx {}", self.tcx.hir_id_to_string(id), self.tag());
             }
         }
     }
@@ -825,15 +828,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let trait_missing_method =
                     matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
-                if item_name.name != kw::Empty {
-                    self.report_method_error(
-                        hir_id,
-                        ty.normalized,
-                        error,
-                        Expectation::NoExpectation,
-                        trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
-                    );
-                }
+                assert_ne!(item_name.name, kw::Empty);
+                self.report_method_error(
+                    hir_id,
+                    ty.normalized,
+                    error,
+                    Expectation::NoExpectation,
+                    trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
+                );
 
                 result
             });
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ac911c20222..b8517701667 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1636,7 +1636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ast::LitKind::Char(_) => tcx.types.char,
             ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)),
             ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)),
-            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
+            ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
                     ty::Int(_) | ty::Uint(_) => Some(ty),
                     // These exist to direct casts like `0x61 as char` to use
@@ -1645,6 +1645,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ty::Char => Some(tcx.types.u8),
                     ty::RawPtr(..) => Some(tcx.types.usize),
                     ty::FnDef(..) | ty::FnPtr(..) => Some(tcx.types.usize),
+                    &ty::Pat(base, _) if base.is_integral() => {
+                        let layout = tcx
+                            .layout_of(self.typing_env(self.param_env).as_query_input(ty))
+                            .ok()?;
+                        assert!(!layout.uninhabited);
+
+                        match layout.backend_repr {
+                            rustc_abi::BackendRepr::Scalar(scalar) => {
+                                scalar.valid_range(&tcx).contains(u128::from(i.get())).then_some(ty)
+                            }
+                            _ => unreachable!(),
+                        }
+                    }
                     _ => None,
                 });
                 opt_ty.unwrap_or_else(|| self.next_int_var())
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 35a3491f7c0..37aaaed5477 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -613,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .iter()
                     .take(4)
                     .map(|(var_hir_id, upvar)| {
-                        let var_name = self.tcx.hir().name(*var_hir_id).to_string();
+                        let var_name = self.tcx.hir_name(*var_hir_id).to_string();
                         let msg = format!("`{var_name}` captured here");
                         (upvar.span, msg)
                     })
diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index 69d7a6c97cb..72f8793d783 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -363,7 +363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let import_items: Vec<_> = applicable_trait
             .import_ids
             .iter()
-            .map(|&import_id| self.tcx.hir().expect_item(import_id))
+            .map(|&import_id| self.tcx.hir_expect_item(import_id))
             .collect();
 
         // Find an identifier with which this trait was imported (note that `_` doesn't count).
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index f87e5b5202a..ee01d78965d 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -2344,7 +2344,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             return false;
         };
         let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
-        let attrs = self.fcx.tcx.hir().attrs(hir_id);
+        let attrs = self.fcx.tcx.hir_attrs(hir_id);
         for attr in attrs {
             if sym::doc == attr.name_or_empty() {
             } else if sym::rustc_confusables == attr.name_or_empty() {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index cb1e89fb9e5..1a1540f505d 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -791,7 +791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let Ok(pick) = self.lookup_probe_for_diagnostic(
                 item_name,
                 Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl),
-                self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)),
+                self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)),
                 ProbeScope::TraitsInScope,
                 None,
             )
@@ -834,8 +834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if let SelfSource::MethodCall(rcvr_expr) = source {
             self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
-                let call_expr =
-                    self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
+                let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
                 let probe = self.lookup_probe_for_diagnostic(
                     item_name,
                     output_ty,
@@ -2373,7 +2372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
+                    let call_expr = tcx.hir_expect_expr(tcx.parent_hir_id(expr.hir_id));
 
                     if let Some(span) = call_expr.span.trim_start(item_name.span) {
                         err.span_suggestion(
@@ -2680,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 mod_id,
                 expr.hir_id,
             ) {
-                let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
+                let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(expr.hir_id));
 
                 let lang_items = self.tcx.lang_items();
                 let never_mention_traits = [
@@ -2757,7 +2756,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let SelfSource::MethodCall(expr) = source else {
             return;
         };
-        let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
+        let call_expr = tcx.hir_expect_expr(tcx.parent_hir_id(expr.hir_id));
 
         let ty::Adt(kind, args) = actual.kind() else {
             return;
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 19ae3e3899c..7e6973259fe 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -87,10 +87,10 @@ struct TopInfo<'tcx> {
 }
 
 #[derive(Copy, Clone)]
-struct PatInfo<'a, 'tcx> {
+struct PatInfo<'tcx> {
     binding_mode: ByRef,
     max_ref_mutbl: MutblCap,
-    top_info: &'a TopInfo<'tcx>,
+    top_info: TopInfo<'tcx>,
     decl_origin: Option<DeclOrigin<'tcx>>,
 
     /// The depth of current pattern
@@ -303,11 +303,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         origin_expr: Option<&'tcx hir::Expr<'tcx>>,
         decl_origin: Option<DeclOrigin<'tcx>>,
     ) {
-        let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
+        let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
         let pat_info = PatInfo {
             binding_mode: ByRef::No,
             max_ref_mutbl: MutblCap::Mut,
-            top_info: &info,
+            top_info,
             decl_origin,
             current_depth: 0,
         };
@@ -320,7 +320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Outside of this module, `check_pat_top` should always be used.
     /// Conversely, inside this module, `check_pat_top` should never be used.
     #[instrument(level = "debug", skip(self, pat_info))]
-    fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
+    fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
         let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
 
         let path_res = match pat.kind {
@@ -352,13 +352,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     qpath,
                     path_res.unwrap(),
                     expected,
-                    ti,
+                    &pat_info.top_info,
                 );
                 self.write_ty(*hir_id, ty);
                 ty
             }
-            PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
-            PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
+            PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info),
+            PatKind::Range(lhs, rhs, _) => {
+                self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info)
+            }
             PatKind::Binding(ba, var_id, ident, sub) => {
                 self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
             }
@@ -818,7 +820,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ident: Ident,
         sub: Option<&'tcx Pat<'tcx>>,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
 
@@ -914,12 +916,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local.
-        let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti);
+        let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti);
 
         // If there are multiple arms, make sure they all agree on
         // what the type of the binding `x` ought to be.
         if var_id != pat.hir_id {
-            self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, ti);
+            self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti);
         }
 
         if let Some(p) = sub {
@@ -1149,7 +1151,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fields: &'tcx [hir::PatField<'tcx>],
         has_rest_pat: bool,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
@@ -1164,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // Type-check the path.
-        let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info);
+        let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
 
         // Type-check subpatterns.
         match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) {
@@ -1353,7 +1355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         subpats: &'tcx [Pat<'tcx>],
         ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let on_error = |e| {
@@ -1403,7 +1405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
 
         // Type-check the tuple struct pattern against the expected type.
-        let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info);
+        let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
         let had_err = diag.map_err(|diag| diag.emit());
 
         // Type-check subpatterns.
@@ -1610,7 +1612,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         elements: &'tcx [Pat<'tcx>],
         ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let mut expected_len = elements.len();
@@ -1625,7 +1627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
         let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
         let pat_ty = Ty::new_tup(tcx, element_tys);
-        if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, pat_info.top_info) {
+        if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) {
             // Walk subpatterns with an expected type of `err` in this case to silence
             // further errors being emitted when using the bindings. #50333
             let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
@@ -1648,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         variant: &'tcx ty::VariantDef,
         fields: &'tcx [hir::PatField<'tcx>],
         has_rest_pat: bool,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Result<(), ErrorGuaranteed> {
         let tcx = self.tcx;
 
@@ -2257,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         inner: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (box_ty, inner_ty) = self
@@ -2267,7 +2269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // think any errors can be introduced by using `demand::eqtype`.
                 let inner_ty = self.next_ty_var(inner.span);
                 let box_ty = Ty::new_box(tcx, inner_ty);
-                self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info)?;
+                self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?;
                 Ok((box_ty, inner_ty))
             })
             .unwrap_or_else(|guar| {
@@ -2283,7 +2285,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         inner: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         // Register a `DerefPure` bound, which is required by all `deref!()` pats.
@@ -2324,7 +2326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         inner: &'tcx Pat<'tcx>,
         pat_mutbl: Mutability,
         mut expected: Ty<'tcx>,
-        mut pat_info: PatInfo<'_, 'tcx>,
+        mut pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
@@ -2482,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             pat.span,
                             expected,
                             ref_ty,
-                            pat_info.top_info,
+                            &pat_info.top_info,
                         );
 
                         // Look for a case like `fn foo(&foo: u32)` and suggest
@@ -2605,7 +2607,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         slice: Option<&'tcx Pat<'tcx>>,
         after: &'tcx [Pat<'tcx>],
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> Ty<'tcx> {
         let expected = self.try_structurally_resolve_type(span, expected);
 
@@ -2767,7 +2769,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         span: Span,
         expected_ty: Ty<'tcx>,
-        pat_info: PatInfo<'_, 'tcx>,
+        pat_info: PatInfo<'tcx>,
     ) -> ErrorGuaranteed {
         let PatInfo { top_info: ti, current_depth, .. } = pat_info;
 
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index f570d0d8a0d..37f3786c00a 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -781,7 +781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
                 base => bug!("Expected upvar, found={:?}", base),
             };
-            let var_ident = self.tcx.hir().ident(var_hir_id);
+            let var_ident = self.tcx.hir_ident(var_hir_id);
 
             let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else {
                 let mutability = self.determine_capture_mutability(&typeck_results, &place);
@@ -988,13 +988,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
                                     let cause_span = self.tcx.hir().span(*capture_expr_id);
                                     lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
-                                        self.tcx.hir().name(*var_hir_id),
+                                        self.tcx.hir_name(*var_hir_id),
                                         captured_name,
                                     ));
                                 }
                                 UpvarMigrationInfo::CapturingNothing { use_span } => {
                                     lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
-                                        self.tcx.hir().name(*var_hir_id),
+                                        self.tcx.hir_name(*var_hir_id),
                                     ));
                                 }
 
@@ -1009,13 +1009,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
                                         lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
-                                            self.tcx.hir().name(*var_hir_id),
+                                            self.tcx.hir_name(*var_hir_id),
                                             captured_name,
                                         ));
                                     }
                                     UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
                                         lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
-                                            v = self.tcx.hir().name(*var_hir_id),
+                                            v = self.tcx.hir_name(*var_hir_id),
                                         ));
                                     }
                                 }
@@ -1026,7 +1026,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 // not capturing something anymore cannot cause a trait to fail to be implemented:
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
-                                        let var_name = self.tcx.hir().name(*var_hir_id);
+                                        let var_name = self.tcx.hir_name(*var_hir_id);
                                         lint.span_label(closure_head_span, format!("\
                                         in Rust 2018, this closure implements {missing_trait} \
                                         as `{var_name}` implements {missing_trait}, but in Rust 2021, \
@@ -2300,7 +2300,7 @@ fn construct_capture_info_string<'tcx>(
 }
 
 fn var_name(tcx: TyCtxt<'_>, var_hir_id: HirId) -> Symbol {
-    tcx.hir().name(var_hir_id)
+    tcx.hir_name(var_hir_id)
 }
 
 #[instrument(level = "debug", skip(tcx))]
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index 4939bfb3a1c..db0a5841887 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-rand = "0.8.4"
+rand = "0.9.0"
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 8f2ca6babea..1b2056f541f 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -123,7 +123,7 @@ impl<'tcx> IfThisChanged<'tcx> {
     fn process_attrs(&mut self, def_id: LocalDefId) {
         let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
         let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
-        let attrs = self.tcx.hir().attrs(hir_id);
+        let attrs = self.tcx.hir_attrs(hir_id);
         for attr in attrs {
             if attr.has_name(sym::rustc_if_this_changed) {
                 let dep_node_interned = self.argument(attr);
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 19cca48af61..76a1ff3cf38 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -108,7 +108,7 @@ use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
-use rand::{RngCore, thread_rng};
+use rand::{RngCore, rng};
 use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::svh::Svh;
@@ -445,7 +445,7 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
 fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
     let timestamp = timestamp_to_string(SystemTime::now());
     debug!("generate_session_dir_path: timestamp = {}", timestamp);
-    let random_number = thread_rng().next_u32();
+    let random_number = rng().next_u32();
     debug!("generate_session_dir_path: random_number = {}", random_number);
 
     // Chop the first 3 characters off the timestamp. Those 3 bytes will be zero for a while.
diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs
index f17ea9e4b59..67ac805c2bf 100644
--- a/compiler/rustc_index/src/slice.rs
+++ b/compiler/rustc_index/src/slice.rs
@@ -1,6 +1,7 @@
 use std::fmt;
 use std::marker::PhantomData;
 use std::ops::{Index, IndexMut};
+use std::slice::GetDisjointMutError::*;
 use std::slice::{self, SliceIndex};
 
 use crate::{Idx, IndexVec, IntoSliceIdx};
@@ -65,6 +66,8 @@ impl<I: Idx, T> IndexSlice<I, T> {
 
     #[inline]
     pub fn iter_enumerated(&self) -> impl DoubleEndedIterator<Item = (I, &T)> + ExactSizeIterator {
+        // Allow the optimizer to elide the bounds checking when creating each index.
+        let _ = I::new(self.len());
         self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
@@ -72,6 +75,8 @@ impl<I: Idx, T> IndexSlice<I, T> {
     pub fn indices(
         &self,
     ) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + Clone + 'static {
+        // Allow the optimizer to elide the bounds checking when creating each index.
+        let _ = I::new(self.len());
         (0..self.len()).map(|n| I::new(n))
     }
 
@@ -84,6 +89,8 @@ impl<I: Idx, T> IndexSlice<I, T> {
     pub fn iter_enumerated_mut(
         &mut self,
     ) -> impl DoubleEndedIterator<Item = (I, &mut T)> + ExactSizeIterator {
+        // Allow the optimizer to elide the bounds checking when creating each index.
+        let _ = I::new(self.len());
         self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
@@ -115,32 +122,36 @@ impl<I: Idx, T> IndexSlice<I, T> {
 
     /// Returns mutable references to two distinct elements, `a` and `b`.
     ///
-    /// Panics if `a == b`.
+    /// Panics if `a == b` or if some of them are out of bounds.
     #[inline]
     pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
         let (ai, bi) = (a.index(), b.index());
-        assert!(ai != bi);
-
-        if ai < bi {
-            let (c1, c2) = self.raw.split_at_mut(bi);
-            (&mut c1[ai], &mut c2[0])
-        } else {
-            let (c2, c1) = self.pick2_mut(b, a);
-            (c1, c2)
+
+        match self.raw.get_disjoint_mut([ai, bi]) {
+            Ok([a, b]) => (a, b),
+            Err(OverlappingIndices) => panic!("Indices {ai:?} and {bi:?} are not disjoint!"),
+            Err(IndexOutOfBounds) => {
+                panic!("Some indices among ({ai:?}, {bi:?}) are out of bounds")
+            }
         }
     }
 
     /// Returns mutable references to three distinct elements.
     ///
-    /// Panics if the elements are not distinct.
+    /// Panics if the elements are not distinct or if some of them are out of bounds.
     #[inline]
     pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
         let (ai, bi, ci) = (a.index(), b.index(), c.index());
-        assert!(ai != bi && bi != ci && ci != ai);
-        let len = self.raw.len();
-        assert!(ai < len && bi < len && ci < len);
-        let ptr = self.raw.as_mut_ptr();
-        unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) }
+
+        match self.raw.get_disjoint_mut([ai, bi, ci]) {
+            Ok([a, b, c]) => (a, b, c),
+            Err(OverlappingIndices) => {
+                panic!("Indices {ai:?}, {bi:?} and {ci:?} are not disjoint!")
+            }
+            Err(IndexOutOfBounds) => {
+                panic!("Some indices among ({ai:?}, {bi:?}, {ci:?}) are out of bounds")
+            }
+        }
     }
 
     #[inline]
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 7f3f3ead5f2..13f0dda180b 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -93,6 +93,8 @@ impl<I: Idx, T> IndexVec<I, T> {
     /// be allocated only once, with a capacity of at least `n`.)
     #[inline]
     pub fn from_fn_n(func: impl FnMut(I) -> T, n: usize) -> Self {
+        // Allow the optimizer to elide the bounds checking when creating each index.
+        let _ = I::new(n);
         IndexVec::from_raw((0..n).map(I::new).map(func).collect())
     }
 
@@ -128,6 +130,8 @@ impl<I: Idx, T> IndexVec<I, T> {
     pub fn into_iter_enumerated(
         self,
     ) -> impl DoubleEndedIterator<Item = (I, T)> + ExactSizeIterator {
+        // Allow the optimizer to elide the bounds checking when creating each index.
+        let _ = I::new(self.len());
         self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 00600abb5f1..a2c1f1dbeda 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -8,7 +8,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
     let mut decls = None;
 
     for id in tcx.hir_free_items() {
-        let attrs = tcx.hir().attrs(id.hir_id());
+        let attrs = tcx.hir_attrs(id.hir_id());
         if attr::contains_name(attrs, sym::rustc_proc_macro_decls) {
             decls = Some(id.owner_id.def_id);
         }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index bc2aae7cd87..5cccab893bb 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -39,11 +39,11 @@ pub(crate) fn add_configuration(
 ) {
     let tf = sym::target_feature;
 
-    let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
-    sess.unstable_target_features.extend(unstable_target_features.iter().cloned());
+    let (target_features, unstable_target_features) = codegen_backend.target_features_cfg(sess);
 
-    let target_features = codegen_backend.target_features_cfg(sess, false);
-    sess.target_features.extend(target_features.iter().cloned());
+    sess.unstable_target_features.extend(unstable_target_features.iter().copied());
+
+    sess.target_features.extend(target_features.iter().copied());
 
     cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index f7be37dc4a2..918a42f3047 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -419,7 +419,7 @@ impl MissingDoc {
             return;
         }
 
-        let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id));
+        let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id));
         let has_doc = attrs.iter().any(has_doc);
         if !has_doc {
             cx.emit_span_lint(
@@ -997,7 +997,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN
 
 impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        let attrs = cx.tcx.hir().attrs(it.hir_id());
+        let attrs = cx.tcx.hir_attrs(it.hir_id());
         let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute,
                                              impl_generics: Option<&hir::Generics<'_>>,
                                              generics: &hir::Generics<'_>,
@@ -1050,7 +1050,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                 for it in *items {
                     if let hir::AssocItemKind::Fn { .. } = it.kind {
                         if let Some(no_mangle_attr) =
-                            attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
+                            attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle)
                         {
                             check_no_mangle_on_generic_fn(
                                 no_mangle_attr,
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index cd4106ebf83..017ae943e91 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -6,6 +6,7 @@
 use std::cell::Cell;
 use std::slice;
 
+use rustc_ast::BindingMode;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync;
 use rustc_data_structures::unord::UnordMap;
@@ -14,6 +15,7 @@ use rustc_feature::Features;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_hir::{Pat, PatKind};
 use rustc_middle::bug;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
@@ -890,7 +892,12 @@ impl<'tcx> LateContext<'tcx> {
             }
             && let Some(init) = match parent_node {
                 hir::Node::Expr(expr) => Some(expr),
-                hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
+                hir::Node::LetStmt(hir::LetStmt {
+                    init,
+                    // Binding is immutable, init cannot be re-assigned
+                    pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
+                    ..
+                }) => *init,
                 _ => None,
             }
         {
@@ -935,7 +942,12 @@ impl<'tcx> LateContext<'tcx> {
             }
             && let Some(init) = match parent_node {
                 hir::Node::Expr(expr) => Some(expr),
-                hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
+                hir::Node::LetStmt(hir::LetStmt {
+                    init,
+                    // Binding is immutable, init cannot be re-assigned
+                    pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
+                    ..
+                }) => *init,
                 hir::Node::Item(item) => match item.kind {
                     hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
                         Some(self.tcx.hir_body(body_id).value)
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index 59e38a882dd..58efca5e994 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
             return;
         }
 
-        // At least one of the fields with a default value have been overriden in
+        // At least one of the fields with a default value have been overridden in
         // the `Default` implementation. We suggest removing it and relying on `..`
         // instead.
         let any_default_field_given =
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 9ca148e1f25..4c2b82a9a23 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -38,7 +38,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
             }
             LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
                 // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
-                let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id();
+                let attr_id = tcx.hir_attrs(hir_id)[attr_index as usize].id();
 
                 (attr_id, lint_index)
             }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 23d6efa0508..852bb01c096 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -48,7 +48,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
     where
         F: FnOnce(&mut Self),
     {
-        let attrs = self.context.tcx.hir().attrs(id);
+        let attrs = self.context.tcx.hir_attrs(id);
         let prev = self.context.last_node_with_lint_attrs;
         self.context.last_node_with_lint_attrs = id;
         debug!("late context: enter_attrs({:?})", attrs);
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 4ede9b44087..aa6eef906ea 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -152,7 +152,7 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
 #[instrument(level = "trace", skip(tcx), ret)]
 fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
     let store = unerased_lint_store(tcx.sess);
-    let attrs = tcx.hir_attrs(owner);
+    let attrs = tcx.hir_attr_map(owner);
 
     let mut levels = LintLevelsBuilder {
         sess: tcx.sess,
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 49f9ad39780..722779d3268 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -342,8 +342,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
         let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
             Some(Ident::from_str(name))
         } else {
-            ast::attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
-                .and_then(|attr| {
+            ast::attr::find_by_name(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), sym::crate_name).and_then(
+                |attr| {
                     if let Attribute::Unparsed(n) = attr
                         && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } =
                             n.as_ref()
@@ -371,7 +371,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
                     } else {
                         None
                     }
-                })
+                },
+            )
         };
 
         if let Some(ident) = &crate_ident {
@@ -500,7 +501,7 @@ impl NonUpperCaseGlobals {
 
 impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        let attrs = cx.tcx.hir().attrs(it.hir_id());
+        let attrs = cx.tcx.hir_attrs(it.hir_id());
         match it.kind {
             hir::ItemKind::Static(..) if !ast::attr::contains_name(attrs, sym::no_mangle) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 7eaf83f5acf..659f6d98f03 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -43,6 +43,7 @@ declare_lint! {
     ///
     /// type Tait = impl Sized;
     ///
+    /// #[define_opaque(Tait)]
     /// fn test() -> impl Trait<Assoc = Tait> {
     ///     42
     /// }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fcadbfc3c4a..6f3c32af5ef 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1589,7 +1589,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
     fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
         let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
-        let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
+        let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
 
         match it.kind {
             hir::ForeignItemKind::Fn(sig, _, _) => {
diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs
index 3c6e30b851b..42d94e72ee9 100644
--- a/compiler/rustc_macros/src/print_attribute.rs
+++ b/compiler/rustc_macros/src/print_attribute.rs
@@ -16,12 +16,14 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 let name = field.ident.as_ref().unwrap();
                 let string_name = name.to_string();
                 disps.push(quote! {
-                    if __printed_anything && #name.print_something() {
-                        __p.word_space(",");
+                    if #name.should_render() {
+                        if __printed_anything {
+                            __p.word_space(",");
+                        }
+                        __p.word(#string_name);
+                        __p.word_space(":");
                         __printed_anything = true;
                     }
-                    __p.word(#string_name);
-                    __p.word_space(":");
                     #name.print_attribute(__p);
                 });
                 field_names.push(name);
@@ -31,10 +33,11 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 quote! { {#(#field_names),*} },
                 quote! {
                     __p.word(#string_name);
-                    if true #(&& !#field_names.print_something())* {
+                    if true #(&& !#field_names.should_render())* {
                         return;
                     }
 
+                    __p.nbsp();
                     __p.word("{");
                     #(#disps)*
                     __p.word("}");
@@ -48,8 +51,10 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
             for idx in 0..fields_unnamed.unnamed.len() {
                 let name = format_ident!("f{idx}");
                 disps.push(quote! {
-                    if __printed_anything && #name.print_something() {
-                        __p.word_space(",");
+                    if #name.should_render() {
+                        if __printed_anything {
+                            __p.word_space(",");
+                        }
                         __printed_anything = true;
                     }
                     #name.print_attribute(__p);
@@ -62,13 +67,13 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
                 quote! {
                     __p.word(#string_name);
 
-                    if true #(&& !#field_names.print_something())* {
+                    if true #(&& !#field_names.should_render())* {
                         return;
                     }
 
-                    __p.word("(");
+                    __p.popen();
                     #(#disps)*
-                    __p.word(")");
+                    __p.pclose();
                 },
                 quote! { true },
             )
@@ -138,7 +143,7 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
     input.gen_impl(quote! {
         #[allow(unused)]
         gen impl PrintAttribute for @Self {
-            fn print_something(&self) -> bool { #printed }
+            fn should_render(&self) -> bool { #printed }
             fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code }
         }
     })
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 582c2215d92..be31aa629c8 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -84,7 +84,7 @@ pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
 fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
     let sess = &tcx.sess;
 
-    if !sess.opts.output_types.should_codegen() {
+    if !sess.opts.output_types.should_link() {
         return IndexVec::new();
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 88a88847e6b..57c941976e4 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1357,8 +1357,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             features: &tcx.features(),
         };
         let attr_iter = tcx
-            .hir()
-            .attrs(tcx.local_def_id_to_hir_id(def_id))
+            .hir_attrs(tcx.local_def_id_to_hir_id(def_id))
             .iter()
             .filter(|attr| analyze_attr(*attr, &mut state));
 
@@ -1839,7 +1838,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_info_for_macro(&mut self, def_id: LocalDefId) {
         let tcx = self.tcx;
 
-        let hir::ItemKind::Macro(macro_def, _) = tcx.hir().expect_item(def_id).kind else { bug!() };
+        let hir::ItemKind::Macro(macro_def, _) = tcx.hir_expect_item(def_id).kind else { bug!() };
         self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules);
         record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body);
     }
@@ -1918,11 +1917,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             for &proc_macro in &tcx.resolutions(()).proc_macros {
                 let id = proc_macro;
                 let proc_macro = tcx.local_def_id_to_hir_id(proc_macro);
-                let mut name = hir.name(proc_macro);
+                let mut name = tcx.hir_name(proc_macro);
                 let span = hir.span(proc_macro);
                 // Proc-macros may have attributes like `#[allow_internal_unstable]`,
                 // so downstream crates need access to them.
-                let attrs = hir.attrs(proc_macro);
+                let attrs = tcx.hir_attrs(proc_macro);
                 let macro_kind = if ast::attr::contains_name(attrs, sym::proc_macro) {
                     MacroKind::Bang
                 } else if ast::attr::contains_name(attrs, sym::proc_macro_attribute) {
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index c85af81ee25..73c0af84a9f 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -275,7 +275,7 @@ impl<'tcx> TyCtxt<'tcx> {
             span_bug!(
                 self.hir().span(hir_id),
                 "body_owned_by: {} has no associated body",
-                self.hir().node_to_string(hir_id)
+                self.hir_id_to_string(hir_id)
             );
         })
     }
@@ -374,7 +374,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
     pub fn hir_krate_attrs(self) -> &'tcx [Attribute] {
-        self.hir().attrs(CRATE_HIR_ID)
+        self.hir_attrs(CRATE_HIR_ID)
     }
 
     pub fn hir_rustc_coherence_is_core(self) -> bool {
@@ -674,104 +674,178 @@ impl<'tcx> TyCtxt<'tcx> {
             }
         }
     }
-}
 
-impl<'hir> Map<'hir> {
-    pub fn get_foreign_abi(self, hir_id: HirId) -> ExternAbi {
-        let parent = self.tcx.hir_get_parent_item(hir_id);
+    /// Get a representation of this `id` for debugging purposes.
+    /// NOTE: Do NOT use this in diagnostics!
+    pub fn hir_id_to_string(self, id: HirId) -> String {
+        let path_str = |def_id: LocalDefId| self.def_path_str(def_id);
+
+        let span_str = || {
+            self.sess.source_map().span_to_snippet(Map { tcx: self }.span(id)).unwrap_or_default()
+        };
+        let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str());
+
+        match self.hir_node(id) {
+            Node::Item(item) => {
+                let item_str = match item.kind {
+                    ItemKind::ExternCrate(..) => "extern crate",
+                    ItemKind::Use(..) => "use",
+                    ItemKind::Static(..) => "static",
+                    ItemKind::Const(..) => "const",
+                    ItemKind::Fn { .. } => "fn",
+                    ItemKind::Macro(..) => "macro",
+                    ItemKind::Mod(..) => "mod",
+                    ItemKind::ForeignMod { .. } => "foreign mod",
+                    ItemKind::GlobalAsm { .. } => "global asm",
+                    ItemKind::TyAlias(..) => "ty",
+                    ItemKind::Enum(..) => "enum",
+                    ItemKind::Struct(..) => "struct",
+                    ItemKind::Union(..) => "union",
+                    ItemKind::Trait(..) => "trait",
+                    ItemKind::TraitAlias(..) => "trait alias",
+                    ItemKind::Impl { .. } => "impl",
+                };
+                format!("{id} ({item_str} {})", path_str(item.owner_id.def_id))
+            }
+            Node::ForeignItem(item) => {
+                format!("{id} (foreign item {})", path_str(item.owner_id.def_id))
+            }
+            Node::ImplItem(ii) => {
+                let kind = match ii.kind {
+                    ImplItemKind::Const(..) => "associated constant",
+                    ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                        ImplicitSelfKind::None => "associated function",
+                        _ => "method",
+                    },
+                    ImplItemKind::Type(_) => "associated type",
+                };
+                format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
+            }
+            Node::TraitItem(ti) => {
+                let kind = match ti.kind {
+                    TraitItemKind::Const(..) => "associated constant",
+                    TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
+                        ImplicitSelfKind::None => "associated function",
+                        _ => "trait method",
+                    },
+                    TraitItemKind::Type(..) => "associated type",
+                };
+
+                format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
+            }
+            Node::Variant(variant) => {
+                format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id))
+            }
+            Node::Field(field) => {
+                format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
+            }
+            Node::AnonConst(_) => node_str("const"),
+            Node::ConstBlock(_) => node_str("const"),
+            Node::ConstArg(_) => node_str("const"),
+            Node::Expr(_) => node_str("expr"),
+            Node::ExprField(_) => node_str("expr field"),
+            Node::Stmt(_) => node_str("stmt"),
+            Node::PathSegment(_) => node_str("path segment"),
+            Node::Ty(_) => node_str("type"),
+            Node::AssocItemConstraint(_) => node_str("assoc item constraint"),
+            Node::TraitRef(_) => node_str("trait ref"),
+            Node::OpaqueTy(_) => node_str("opaque type"),
+            Node::Pat(_) => node_str("pat"),
+            Node::TyPat(_) => node_str("pat ty"),
+            Node::PatField(_) => node_str("pattern field"),
+            Node::PatExpr(_) => node_str("pattern literal"),
+            Node::Param(_) => node_str("param"),
+            Node::Arm(_) => node_str("arm"),
+            Node::Block(_) => node_str("block"),
+            Node::Infer(_) => node_str("infer"),
+            Node::LetStmt(_) => node_str("local"),
+            Node::Ctor(ctor) => format!(
+                "{id} (ctor {})",
+                ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)),
+            ),
+            Node::Lifetime(_) => node_str("lifetime"),
+            Node::GenericParam(param) => {
+                format!("{id} (generic_param {})", path_str(param.def_id))
+            }
+            Node::Crate(..) => String::from("(root_crate)"),
+            Node::WherePredicate(_) => node_str("where predicate"),
+            Node::Synthetic => unreachable!(),
+            Node::Err(_) => node_str("error"),
+            Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"),
+        }
+    }
+
+    pub fn hir_get_foreign_abi(self, hir_id: HirId) -> ExternAbi {
+        let parent = self.hir_get_parent_item(hir_id);
         if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) =
-            self.tcx.hir_owner_node(parent)
+            self.hir_owner_node(parent)
         {
             return *abi;
         }
         bug!(
             "expected foreign mod or inlined parent, found {}",
-            self.node_to_string(HirId::make_owner(parent.def_id))
+            self.hir_id_to_string(HirId::make_owner(parent.def_id))
         )
     }
 
-    pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
-        match self.tcx.expect_hir_owner_node(id) {
+    pub fn hir_expect_item(self, id: LocalDefId) -> &'tcx Item<'tcx> {
+        match self.expect_hir_owner_node(id) {
             OwnerNode::Item(item) => item,
-            _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
+            _ => bug!("expected item, found {}", self.hir_id_to_string(HirId::make_owner(id))),
         }
     }
 
-    pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
-        match self.tcx.expect_hir_owner_node(id) {
+    pub fn hir_expect_impl_item(self, id: LocalDefId) -> &'tcx ImplItem<'tcx> {
+        match self.expect_hir_owner_node(id) {
             OwnerNode::ImplItem(item) => item,
-            _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
+            _ => bug!("expected impl item, found {}", self.hir_id_to_string(HirId::make_owner(id))),
         }
     }
 
-    pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
-        match self.tcx.expect_hir_owner_node(id) {
+    pub fn hir_expect_trait_item(self, id: LocalDefId) -> &'tcx TraitItem<'tcx> {
+        match self.expect_hir_owner_node(id) {
             OwnerNode::TraitItem(item) => item,
-            _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
-        }
-    }
-
-    pub fn get_fn_output(self, def_id: LocalDefId) -> Option<&'hir FnRetTy<'hir>> {
-        Some(&self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.output)
-    }
-
-    pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> {
-        match self.tcx.hir_node(id) {
-            Node::Variant(variant) => variant,
-            _ => bug!("expected variant, found {}", self.node_to_string(id)),
-        }
-    }
-
-    pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> {
-        match self.tcx.hir_node(id) {
-            Node::Field(field) => field,
-            _ => bug!("expected field, found {}", self.node_to_string(id)),
-        }
-    }
-
-    pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
-        match self.tcx.hir_owner_node(id) {
-            OwnerNode::ForeignItem(item) => item,
             _ => {
-                bug!(
-                    "expected foreign item, found {}",
-                    self.node_to_string(HirId::make_owner(id.def_id))
-                )
+                bug!("expected trait item, found {}", self.hir_id_to_string(HirId::make_owner(id)))
             }
         }
     }
 
+    pub fn hir_get_fn_output(self, def_id: LocalDefId) -> Option<&'tcx FnRetTy<'tcx>> {
+        Some(&self.opt_hir_owner_node(def_id)?.fn_decl()?.output)
+    }
+
     #[track_caller]
-    pub fn expect_opaque_ty(self, id: LocalDefId) -> &'hir OpaqueTy<'hir> {
-        match self.tcx.hir_node_by_def_id(id) {
+    pub fn hir_expect_opaque_ty(self, id: LocalDefId) -> &'tcx OpaqueTy<'tcx> {
+        match self.hir_node_by_def_id(id) {
             Node::OpaqueTy(opaq) => opaq,
             _ => {
                 bug!(
                     "expected opaque type definition, found {}",
-                    self.node_to_string(self.tcx.local_def_id_to_hir_id(id))
+                    self.hir_id_to_string(self.local_def_id_to_hir_id(id))
                 )
             }
         }
     }
 
-    pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
-        match self.tcx.hir_node(id) {
+    pub fn hir_expect_expr(self, id: HirId) -> &'tcx Expr<'tcx> {
+        match self.hir_node(id) {
             Node::Expr(expr) => expr,
-            _ => bug!("expected expr, found {}", self.node_to_string(id)),
+            _ => bug!("expected expr, found {}", self.hir_id_to_string(id)),
         }
     }
 
-    pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option<DefId> {
-        self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id()
+    pub fn hir_opt_delegation_sig_id(self, def_id: LocalDefId) -> Option<DefId> {
+        self.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id()
     }
 
     #[inline]
-    fn opt_ident(self, id: HirId) -> Option<Ident> {
-        match self.tcx.hir_node(id) {
+    fn hir_opt_ident(self, id: HirId) -> Option<Ident> {
+        match self.hir_node(id) {
             Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
             // A `Ctor` doesn't have an identifier itself, but its parent
             // struct/variant does. Compare with `hir::Map::span`.
-            Node::Ctor(..) => match self.tcx.parent_hir_node(id) {
+            Node::Ctor(..) => match self.parent_hir_node(id) {
                 Node::Item(item) => Some(item.ident),
                 Node::Variant(variant) => Some(variant.ident),
                 _ => unreachable!(),
@@ -781,30 +855,32 @@ impl<'hir> Map<'hir> {
     }
 
     #[inline]
-    pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> {
-        self.opt_ident(id).map(|ident| ident.span)
+    pub(super) fn hir_opt_ident_span(self, id: HirId) -> Option<Span> {
+        self.hir_opt_ident(id).map(|ident| ident.span)
     }
 
     #[inline]
-    pub fn ident(self, id: HirId) -> Ident {
-        self.opt_ident(id).unwrap()
+    pub fn hir_ident(self, id: HirId) -> Ident {
+        self.hir_opt_ident(id).unwrap()
     }
 
     #[inline]
-    pub fn opt_name(self, id: HirId) -> Option<Symbol> {
-        self.opt_ident(id).map(|ident| ident.name)
+    pub fn hir_opt_name(self, id: HirId) -> Option<Symbol> {
+        self.hir_opt_ident(id).map(|ident| ident.name)
     }
 
-    pub fn name(self, id: HirId) -> Symbol {
-        self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id)))
+    pub fn hir_name(self, id: HirId) -> Symbol {
+        self.hir_opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.hir_id_to_string(id)))
     }
 
     /// Given a node ID, gets a list of attributes associated with the AST
     /// corresponding to the node-ID.
-    pub fn attrs(self, id: HirId) -> &'hir [Attribute] {
-        self.tcx.hir_attrs(id.owner).get(id.local_id)
+    pub fn hir_attrs(self, id: HirId) -> &'tcx [Attribute] {
+        self.hir_attr_map(id.owner).get(id.local_id)
     }
+}
 
+impl<'hir> Map<'hir> {
     /// Gets the span of the definition of the specified HIR node.
     /// This is used by `tcx.def_span`.
     pub fn span(self, hir_id: HirId) -> Span {
@@ -977,12 +1053,6 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Get a representation of this `id` for debugging purposes.
-    /// NOTE: Do NOT use this in diagnostics!
-    pub fn node_to_string(self, id: HirId) -> String {
-        hir_id_to_string(self, id)
-    }
-
     /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
     /// called with the HirId for the `{ ... }` anon const
     pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
@@ -1147,102 +1217,6 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
     upstream_crates
 }
 
-fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
-    let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id);
-
-    let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default();
-    let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str());
-
-    match map.tcx.hir_node(id) {
-        Node::Item(item) => {
-            let item_str = match item.kind {
-                ItemKind::ExternCrate(..) => "extern crate",
-                ItemKind::Use(..) => "use",
-                ItemKind::Static(..) => "static",
-                ItemKind::Const(..) => "const",
-                ItemKind::Fn { .. } => "fn",
-                ItemKind::Macro(..) => "macro",
-                ItemKind::Mod(..) => "mod",
-                ItemKind::ForeignMod { .. } => "foreign mod",
-                ItemKind::GlobalAsm { .. } => "global asm",
-                ItemKind::TyAlias(..) => "ty",
-                ItemKind::Enum(..) => "enum",
-                ItemKind::Struct(..) => "struct",
-                ItemKind::Union(..) => "union",
-                ItemKind::Trait(..) => "trait",
-                ItemKind::TraitAlias(..) => "trait alias",
-                ItemKind::Impl { .. } => "impl",
-            };
-            format!("{id} ({item_str} {})", path_str(item.owner_id.def_id))
-        }
-        Node::ForeignItem(item) => {
-            format!("{id} (foreign item {})", path_str(item.owner_id.def_id))
-        }
-        Node::ImplItem(ii) => {
-            let kind = match ii.kind {
-                ImplItemKind::Const(..) => "associated constant",
-                ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
-                    ImplicitSelfKind::None => "associated function",
-                    _ => "method",
-                },
-                ImplItemKind::Type(_) => "associated type",
-            };
-            format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id))
-        }
-        Node::TraitItem(ti) => {
-            let kind = match ti.kind {
-                TraitItemKind::Const(..) => "associated constant",
-                TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self {
-                    ImplicitSelfKind::None => "associated function",
-                    _ => "trait method",
-                },
-                TraitItemKind::Type(..) => "associated type",
-            };
-
-            format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id))
-        }
-        Node::Variant(variant) => {
-            format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id))
-        }
-        Node::Field(field) => {
-            format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
-        }
-        Node::AnonConst(_) => node_str("const"),
-        Node::ConstBlock(_) => node_str("const"),
-        Node::ConstArg(_) => node_str("const"),
-        Node::Expr(_) => node_str("expr"),
-        Node::ExprField(_) => node_str("expr field"),
-        Node::Stmt(_) => node_str("stmt"),
-        Node::PathSegment(_) => node_str("path segment"),
-        Node::Ty(_) => node_str("type"),
-        Node::AssocItemConstraint(_) => node_str("assoc item constraint"),
-        Node::TraitRef(_) => node_str("trait ref"),
-        Node::OpaqueTy(_) => node_str("opaque type"),
-        Node::Pat(_) => node_str("pat"),
-        Node::TyPat(_) => node_str("pat ty"),
-        Node::PatField(_) => node_str("pattern field"),
-        Node::PatExpr(_) => node_str("pattern literal"),
-        Node::Param(_) => node_str("param"),
-        Node::Arm(_) => node_str("arm"),
-        Node::Block(_) => node_str("block"),
-        Node::Infer(_) => node_str("infer"),
-        Node::LetStmt(_) => node_str("local"),
-        Node::Ctor(ctor) => format!(
-            "{id} (ctor {})",
-            ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)),
-        ),
-        Node::Lifetime(_) => node_str("lifetime"),
-        Node::GenericParam(param) => {
-            format!("{id} (generic_param {})", path_str(param.def_id))
-        }
-        Node::Crate(..) => String::from("(root_crate)"),
-        Node::WherePredicate(_) => node_str("where predicate"),
-        Node::Synthetic => unreachable!(),
-        Node::Err(_) => node_str("error"),
-        Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"),
-    }
-}
-
 pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems {
     let mut collector = ItemCollector::new(tcx, false);
 
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 6071a58367e..68b9a4f56b9 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -202,13 +202,13 @@ pub fn provide(providers: &mut Providers) {
             }
         })
     };
-    providers.hir_attrs = |tcx, id| {
+    providers.hir_attr_map = |tcx, id| {
         tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
     };
     providers.def_span = |tcx, def_id| tcx.hir().span(tcx.local_def_id_to_hir_id(def_id));
     providers.def_ident_span = |tcx, def_id| {
         let hir_id = tcx.local_def_id_to_hir_id(def_id);
-        tcx.hir().opt_ident_span(hir_id)
+        tcx.hir_opt_ident_span(hir_id)
     };
     providers.fn_arg_names = |tcx, def_id| {
         let hir = tcx.hir();
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index ba65a711815..b24f6bc7770 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -679,6 +679,11 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         // Set provenance of all bytes to wildcard.
         self.provenance.write_wildcards(self.len());
 
+        // Also expose the provenance of the interpreter-level allocation, so it can
+        // be written by FFI. The `black_box` is defensive programming as LLVM likes
+        // to (incorrectly) optimize away ptr2int casts whose result is unused.
+        std::hint::black_box(self.get_bytes_unchecked_raw_mut().expose_provenance());
+
         Ok(())
     }
 
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index f880b1364c2..573f7895da2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -653,7 +653,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
             write!(w, "static mut ")?
         }
         (_, _) if is_function => write!(w, "fn ")?,
-        (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
+        // things like anon const, not an item
+        (DefKind::AnonConst | DefKind::InlineConst, _) => {}
+        // `global_asm!` have fake bodies, which we may dump after mir-build
+        (DefKind::GlobalAsm, _) => {}
         _ => bug!("Unexpected def kind {:?}", kind),
     }
 
@@ -1200,7 +1203,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                             && let Some(upvars) = tcx.upvars_mentioned(def_id)
                         {
                             for (&var_id, place) in iter::zip(upvars.keys(), places) {
-                                let var_name = tcx.hir().name(var_id);
+                                let var_name = tcx.hir_name(var_id);
                                 struct_fmt.field(var_name.as_str(), place);
                             }
                         } else {
@@ -1221,7 +1224,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                             && let Some(upvars) = tcx.upvars_mentioned(def_id)
                         {
                             for (&var_id, place) in iter::zip(upvars.keys(), places) {
-                                let var_name = tcx.hir().name(var_id);
+                                let var_name = tcx.hir_name(var_id);
                                 struct_fmt.field(var_name.as_str(), place);
                             }
                         } else {
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index bc77f22af67..b2c51ad8864 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -454,6 +454,7 @@ mod helper {
         /// Like [`SwitchTargets::target_for_value`], but returning the same type as
         /// [`Terminator::successors`].
         #[inline]
+        #[cfg_attr(not(bootstrap), define_opaque(Successors))]
         pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
             let target = self.target_for_value(value);
             (&[]).into_iter().copied().chain(Some(target))
@@ -462,6 +463,7 @@ mod helper {
 
     impl<'tcx> TerminatorKind<'tcx> {
         #[inline]
+        #[cfg_attr(not(bootstrap), define_opaque(Successors))]
         pub fn successors(&self) -> Successors<'_> {
             use self::TerminatorKind::*;
             match *self {
@@ -500,6 +502,7 @@ mod helper {
         }
 
         #[inline]
+        #[cfg_attr(not(bootstrap), define_opaque(SuccessorsMut))]
         pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
             use self::TerminatorKind::*;
             match *self {
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 907618e428f..7bbaa0496d5 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -24,6 +24,7 @@ pub trait EraseType: Copy {
 pub type Erase<T: EraseType> = Erased<impl Copy>;
 
 #[inline(always)]
+#[cfg_attr(not(bootstrap), define_opaque(Erase))]
 pub fn erase<T: EraseType>(src: T) -> Erase<T> {
     // Ensure the sizes match
     const {
@@ -47,6 +48,7 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> {
 
 /// Restores an erased value.
 #[inline(always)]
+#[cfg_attr(not(bootstrap), define_opaque(Erase))]
 pub fn restore<T: EraseType>(value: Erase<T>) -> T {
     let value: Erased<<T as EraseType>::Result> = value;
     // See comment in `erase` for why we use `transmute_unchecked`.
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c8708857565..781a898a6e9 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -198,7 +198,7 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
+    query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
         desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
         feedable
     }
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 9ce5373b031..8e54a9d487d 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -72,7 +72,7 @@ impl OverlapMode {
                     .as_local()
                     .into_iter()
                     .flat_map(|local_def_id| {
-                        tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id))
+                        tcx.hir_attrs(tcx.local_def_id_to_hir_id(local_def_id))
                     })
                     .find(|attr| attr.has_name(sym::rustc_strict_coherence))
                     .map(|attr| attr.span());
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 3585f28b4a5..c1dc6a894ca 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -53,8 +53,6 @@ bitflags::bitflags! {
         const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
         /// Indicates whether the type is `UnsafeCell`.
         const IS_UNSAFE_CELL              = 1 << 9;
-        /// Indicates whether the type is anonymous.
-        const IS_ANONYMOUS                = 1 << 10;
     }
 }
 rustc_data_structures::external_bitflags_debug! { AdtFlags }
@@ -402,12 +400,6 @@ impl<'tcx> AdtDef<'tcx> {
         self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
     }
 
-    /// Returns `true` if this is an anonymous adt
-    #[inline]
-    pub fn is_anonymous(self) -> bool {
-        self.flags().contains(AdtFlags::IS_ANONYMOUS)
-    }
-
     /// Returns `true` if this type has a destructor.
     pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
         self.destructor(tcx).is_some()
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 5d9b1ddfa38..703b6ce9247 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -296,7 +296,7 @@ pub struct CaptureInfo {
 
 pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
     let mut curr_string: String = match place.base {
-        HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
+        HirPlaceBase::Upvar(upvar_id) => tcx.hir_name(upvar_id.var_path.hir_id).to_string(),
         _ => bug!("Capture_information should only contain upvars"),
     };
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index edba2a2530f..544a6cb64f3 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1299,7 +1299,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
             ),
             bodies,
         })));
-        self.feed_owner_id().hir_attrs(attrs);
+        self.feed_owner_id().hir_attr_map(attrs);
     }
 }
 
@@ -2214,7 +2214,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Returns the origin of the opaque type `def_id`.
     #[instrument(skip(self), level = "trace", ret)]
     pub fn local_opaque_ty_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin<LocalDefId> {
-        self.hir().expect_opaque_ty(def_id).origin
+        self.hir_expect_opaque_ty(def_id).origin
     }
 
     pub fn finish(self) {
@@ -3118,9 +3118,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
         self.mk_bound_variable_kinds(
-            &self.late_bound_vars_map(id.owner).get(&id.local_id).cloned().unwrap_or_else(|| {
-                bug!("No bound vars found for {}", self.hir().node_to_string(id))
-            }),
+            &self
+                .late_bound_vars_map(id.owner)
+                .get(&id.local_id)
+                .cloned()
+                .unwrap_or_else(|| bug!("No bound vars found for {}", self.hir_id_to_string(id))),
         )
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c5509c0a608..ad9d32fd6c1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1151,7 +1151,7 @@ pub struct VariantDef {
     /// `DefId` that identifies the variant's constructor.
     /// If this variant is a struct variant, then this is `None`.
     pub ctor: Option<(CtorKind, DefId)>,
-    /// Variant or struct name, maybe empty for anonymous adt (struct or union).
+    /// Variant or struct name.
     pub name: Symbol,
     /// Discriminant of this variant.
     pub discr: VariantDiscr,
@@ -1696,7 +1696,7 @@ impl<'tcx> TyCtxt<'tcx> {
     // FIXME(@lcnr): Remove this function.
     pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [hir::Attribute] {
         if let Some(did) = did.as_local() {
-            self.hir().attrs(self.local_def_id_to_hir_id(did))
+            self.hir_attrs(self.local_def_id_to_hir_id(did))
         } else {
             self.attrs_for_def(did)
         }
@@ -1720,7 +1720,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> impl Iterator<Item = &'tcx hir::Attribute> {
         let did: DefId = did.into();
         if let Some(did) = did.as_local() {
-            self.hir().attrs(self.local_def_id_to_hir_id(did)).iter()
+            self.hir_attrs(self.local_def_id_to_hir_id(did)).iter()
         } else {
             self.attrs_for_def(did).iter()
         }
@@ -1764,7 +1764,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> impl Iterator<Item = &'tcx hir::Attribute> {
         let filter_fn = move |a: &&hir::Attribute| a.path_matches(attr);
         if let Some(did) = did.as_local() {
-            self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+            self.hir_attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
         } else {
             self.attrs_for_def(did).iter().filter(filter_fn)
         }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 6c62c04f42e..f1d03d0a659 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -50,7 +50,7 @@ impl<'tcx> fmt::Debug for ty::AdtDef<'tcx> {
 
 impl fmt::Debug for ty::UpvarId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let name = ty::tls::with(|tcx| tcx.hir().name(self.var_path.hir_id));
+        let name = ty::tls::with(|tcx| tcx.hir_name(self.var_path.hir_id));
         write!(f, "UpvarId({:?};`{}`;{:?})", self.var_path.hir_id, name, self.closure_expr_id)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 7d9c23c05f9..06054e22e76 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -310,7 +310,7 @@ impl<'tcx> TypeckResults<'tcx> {
 
     pub fn node_type(&self, id: HirId) -> Ty<'tcx> {
         self.node_type_opt(id).unwrap_or_else(|| {
-            bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir().node_to_string(id)))
+            bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir_id_to_string(id)))
         })
     }
 
@@ -554,7 +554,7 @@ fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: HirId) {
     ty::tls::with(|tcx| {
         bug!(
             "node {} cannot be placed in TypeckResults with hir_owner {:?}",
-            tcx.hir().node_to_string(hir_id),
+            tcx.hir_id_to_string(hir_id),
             hir_owner
         )
     });
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
index 84c9297e658..f743ea60a45 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
@@ -117,7 +117,12 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
         ConstValue::Scalar(Scalar::from_uint(result, width))
     };
 
-    let value = match (lit, ty.kind()) {
+    let lit_ty = match *ty.kind() {
+        ty::Pat(base, _) => base,
+        _ => ty,
+    };
+
+    let value = match (lit, lit_ty.kind()) {
         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
             let s = s.as_str();
             let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index f9fa750e750..2909dea98b7 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -485,7 +485,7 @@ fn construct_fn<'tcx>(
     };
 
     if let Some(custom_mir_attr) =
-        tcx.hir().attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir)
+        tcx.hir_attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir)
     {
         return custom::build_custom_mir(
             tcx,
@@ -741,7 +741,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         coroutine: Option<Box<CoroutineInfo<'tcx>>>,
     ) -> Builder<'a, 'tcx> {
         let tcx = infcx.tcx;
-        let attrs = tcx.hir().attrs(hir_id);
+        let attrs = tcx.hir_attrs(hir_id);
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
         // the settings for the crate they are codegened in.
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index 81561239491..27ff01b4803 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -942,14 +942,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         assert_eq!(orig_id.owner, self.hir_id.owner);
 
         let mut id = orig_id;
-        let hir = self.tcx.hir();
         loop {
             if id == self.hir_id {
                 // This is a moderately common case, mostly hit for previously unseen nodes.
                 break;
             }
 
-            if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
+            if self.tcx.hir_attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
                 // This is a rare case. It's for a node path that doesn't reach the root due to an
                 // intervening lint level attribute. This result doesn't get cached.
                 return id;
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index e46e8c9871a..b8af77245f2 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1041,7 +1041,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
                         "Should have already errored about late bound consts: {def_id:?}"
                     );
                 };
-                let name = self.tcx.hir().name(hir_id);
+                let name = self.tcx.hir_name(hir_id);
                 let param = ty::ParamConst::new(index, name);
 
                 ExprKind::ConstParam { param, def_id }
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 2e069cae426..b3daed8a7e0 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -73,7 +73,6 @@ struct ThirBuildCx<'tcx> {
 impl<'tcx> ThirBuildCx<'tcx> {
     fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self {
         let typeck_results = tcx.typeck(def);
-        let hir = tcx.hir();
         let hir_id = tcx.local_def_id_to_hir_id(def);
 
         let body_type = match tcx.hir_body_owner_kind(def) {
@@ -111,8 +110,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
             typeck_results,
             rvalue_scopes: &typeck_results.rvalue_scopes,
             body_owner: def.to_def_id(),
-            apply_adjustments: hir
-                .attrs(hir_id)
+            apply_adjustments: tcx
+                .hir_attrs(hir_id)
                 .iter()
                 .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
         }
@@ -207,7 +206,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
         &self,
         hir_id: HirId,
     ) -> Option<ty::CanonicalUserType<'tcx>> {
-        crate::thir::util::user_args_applied_to_ty_of_hir_id(self.typeck_results, hir_id)
+        crate::thir::util::user_args_applied_to_ty_of_hir_id(self.tcx, self.typeck_results, hir_id)
     }
 }
 
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 dadd1e85461..cbd29ba837e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1043,7 +1043,7 @@ fn find_fallback_pattern_typo<'tcx>(
         for item in cx.tcx.hir_crate_items(()).free_items() {
             if let DefKind::Use = cx.tcx.def_kind(item.owner_id) {
                 // Look for consts being re-exported.
-                let item = cx.tcx.hir().expect_item(item.owner_id.def_id);
+                let item = cx.tcx.hir_expect_item(item.owner_id.def_id);
                 let use_name = item.ident.name;
                 let hir::ItemKind::Use(path, _) = item.kind else {
                     continue;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 8dc3f998e09..4bfeab44bf4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -539,7 +539,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         &self,
         hir_id: hir::HirId,
     ) -> Option<ty::CanonicalUserType<'tcx>> {
-        crate::thir::util::user_args_applied_to_ty_of_hir_id(self.typeck_results, hir_id)
+        crate::thir::util::user_args_applied_to_ty_of_hir_id(self.tcx, self.typeck_results, hir_id)
     }
 
     /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs
index 60a47a94e3a..457957f5fce 100644
--- a/compiler/rustc_mir_build/src/thir/util.rs
+++ b/compiler/rustc_mir_build/src/thir/util.rs
@@ -1,12 +1,16 @@
+use std::assert_matches::assert_matches;
+
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, CanonicalUserType};
+use rustc_middle::ty::{self, CanonicalUserType, TyCtxt};
 use tracing::debug;
 
 /// Looks up the type associated with this hir-id and applies the
 /// user-given generic parameters; the hir-id must map to a suitable
 /// type.
 pub(crate) fn user_args_applied_to_ty_of_hir_id<'tcx>(
+    tcx: TyCtxt<'tcx>,
     typeck_results: &ty::TypeckResults<'tcx>,
     hir_id: hir::HirId,
 ) -> Option<CanonicalUserType<'tcx>> {
@@ -16,7 +20,23 @@ pub(crate) fn user_args_applied_to_ty_of_hir_id<'tcx>(
     let ty = typeck_results.node_type(hir_id);
     match ty.kind() {
         ty::Adt(adt_def, ..) => {
+            // This "fixes" user type annotations for tupled ctor patterns for ADTs.
+            // That's because `type_of(ctor_did)` returns a FnDef, but we actually
+            // want to be annotating the type of the ADT itself. It's a bit goofy,
+            // but it's easier to adjust this here rather than in the path lowering
+            // code for patterns in HIR.
             if let ty::UserTypeKind::TypeOf(did, _) = &mut user_ty.value.kind {
+                // This is either already set up correctly (struct, union, enum, or variant),
+                // or needs adjusting (ctor). Make sure we don't start adjusting other
+                // user annotations like consts or fn calls.
+                assert_matches!(
+                    tcx.def_kind(*did),
+                    DefKind::Ctor(..)
+                        | DefKind::Struct
+                        | DefKind::Enum
+                        | DefKind::Union
+                        | DefKind::Variant
+                );
                 *did = adt_def.did();
             }
             Some(user_ty)
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index bb227a58cf1..716ababb008 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2107,7 +2107,7 @@ impl<'a> Parser<'a> {
                     ast::GenericBound::Trait(poly) => Some(poly),
                     _ => None,
                 })
-                .last()
+                .next_back()
         {
             err.span_suggestion_verbose(
                 poly.span.shrink_to_hi(),
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 0b9350c7199..9e6cdfe59bb 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -217,7 +217,14 @@ impl<'a> Parser<'a> {
                 self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
             (
                 ident,
-                ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, contract, body })),
+                ItemKind::Fn(Box::new(Fn {
+                    defaultness: def_(),
+                    sig,
+                    generics,
+                    contract,
+                    body,
+                    define_opaque: None,
+                })),
             )
         } else if self.eat_keyword(exp!(Extern)) {
             if self.eat_keyword(exp!(Crate)) {
@@ -639,7 +646,7 @@ impl<'a> Parser<'a> {
 
         let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?;
 
-        let item_kind = match ty_second {
+        let (of_trait, self_ty) = match ty_second {
             Some(ty_second) => {
                 // impl Trait for Type
                 if !has_for {
@@ -672,31 +679,20 @@ impl<'a> Parser<'a> {
                 };
                 let trait_ref = TraitRef { path, ref_id: ty_first.id };
 
-                ItemKind::Impl(Box::new(Impl {
-                    safety,
-                    polarity,
-                    defaultness,
-                    constness,
-                    generics,
-                    of_trait: Some(trait_ref),
-                    self_ty: ty_second,
-                    items: impl_items,
-                }))
-            }
-            None => {
-                // impl Type
-                ItemKind::Impl(Box::new(Impl {
-                    safety,
-                    polarity,
-                    defaultness,
-                    constness,
-                    generics,
-                    of_trait: None,
-                    self_ty: ty_first,
-                    items: impl_items,
-                }))
+                (Some(trait_ref), ty_second)
             }
+            None => (None, ty_first), // impl Type
         };
+        let item_kind = ItemKind::Impl(Box::new(Impl {
+            safety,
+            polarity,
+            defaultness,
+            constness,
+            generics,
+            of_trait,
+            self_ty,
+            items: impl_items,
+        }));
 
         Ok((Ident::empty(), item_kind))
     }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 287bd8678da..5b8a2fe52d3 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -189,7 +189,7 @@ pub enum DebugHex {
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum Count<'a> {
     /// The count is specified explicitly.
-    CountIs(usize),
+    CountIs(u16),
     /// The count is specified by the argument with the given name.
     CountIsName(&'a str, InnerSpan),
     /// The count is specified by the argument at the given index.
@@ -564,7 +564,7 @@ impl<'a> Parser<'a> {
     /// consuming a macro argument, `None` if it's the case.
     fn position(&mut self) -> Option<Position<'a>> {
         if let Some(i) = self.integer() {
-            Some(ArgumentIs(i))
+            Some(ArgumentIs(i.into()))
         } else {
             match self.cur.peek() {
                 Some(&(lo, c)) if rustc_lexer::is_id_start(c) => {
@@ -770,7 +770,7 @@ impl<'a> Parser<'a> {
     /// width.
     fn count(&mut self, start: usize) -> Count<'a> {
         if let Some(i) = self.integer() {
-            if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
+            if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) }
         } else {
             let tmp = self.cur.clone();
             let word = self.word();
@@ -821,15 +821,15 @@ impl<'a> Parser<'a> {
         word
     }
 
-    fn integer(&mut self) -> Option<usize> {
-        let mut cur: usize = 0;
+    fn integer(&mut self) -> Option<u16> {
+        let mut cur: u16 = 0;
         let mut found = false;
         let mut overflow = false;
         let start = self.current_pos();
         while let Some(&(_, c)) = self.cur.peek() {
             if let Some(i) = c.to_digit(10) {
                 let (tmp, mul_overflow) = cur.overflowing_mul(10);
-                let (tmp, add_overflow) = tmp.overflowing_add(i as usize);
+                let (tmp, add_overflow) = tmp.overflowing_add(i as u16);
                 if mul_overflow || add_overflow {
                     overflow = true;
                 }
@@ -846,11 +846,11 @@ impl<'a> Parser<'a> {
             let overflowed_int = &self.input[start..end];
             self.err(
                 format!(
-                    "integer `{}` does not fit into the type `usize` whose range is `0..={}`",
+                    "integer `{}` does not fit into the type `u16` whose range is `0..={}`",
                     overflowed_int,
-                    usize::MAX
+                    u16::MAX
                 ),
-                "integer out of range for `usize`",
+                "integer out of range for `u16`",
                 self.span(start, end),
             );
         }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c6ae2c0fb9b..ece5a53aaa9 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -52,7 +52,7 @@ fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>)
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
             let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
-            let containing_item = tcx.hir().expect_item(parent_def_id);
+            let containing_item = tcx.hir_expect_item(parent_def_id);
             let containing_impl_is_for_trait = match &containing_item.kind {
                 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
                 _ => bug!("parent of an ImplItem must be an Impl"),
@@ -114,7 +114,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let mut doc_aliases = FxHashMap::default();
         let mut specified_inline = None;
         let mut seen = FxHashMap::default();
-        let attrs = self.tcx.hir().attrs(hir_id);
+        let attrs = self.tcx.hir_attrs(hir_id);
         for attr in attrs {
             match attr {
                 Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
@@ -899,7 +899,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         if let Some(location) = match target {
             Target::AssocTy => {
                 let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
-                let containing_item = self.tcx.hir().expect_item(parent_def_id);
+                let containing_item = self.tcx.hir_expect_item(parent_def_id);
                 if Target::from_item(containing_item) == Target::Impl {
                     Some("type alias in implementation block")
                 } else {
@@ -908,7 +908,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
             Target::AssocConst => {
                 let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
-                let containing_item = self.tcx.hir().expect_item(parent_def_id);
+                let containing_item = self.tcx.hir_expect_item(parent_def_id);
                 // We can't link to trait impl's consts.
                 let err = "associated constant in trait implementation block";
                 match containing_item.kind {
@@ -952,7 +952,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location });
             return;
         }
-        let item_name = self.tcx.hir().name(hir_id);
+        let item_name = self.tcx.hir_name(hir_id);
         if item_name == doc_alias {
             tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str });
             return;
@@ -1481,7 +1481,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         // `#[must_use]` can be applied to a trait method definition with a default body
         if let Target::Method(MethodKind::Trait { body: true }) = target
             && let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id
-            && let containing_item = self.tcx.hir().expect_item(parent_def_id)
+            && let containing_item = self.tcx.hir_expect_item(parent_def_id)
             && let hir::ItemKind::Trait(..) = containing_item.kind
         {
             return;
@@ -2572,7 +2572,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match (target, force_inline_attr) {
             (Target::Closure, None) => {
                 let is_coro = matches!(
-                    self.tcx.hir().expect_expr(hir_id).kind,
+                    self.tcx.hir_expect_expr(hir_id).kind,
                     hir::ExprKind::Closure(hir::Closure {
                         kind: hir::ClosureKind::Coroutine(..)
                             | hir::ClosureKind::CoroutineClosure(..),
@@ -2644,8 +2644,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr];
         let spans = self
             .tcx
-            .hir()
-            .attrs(where_predicate.hir_id)
+            .hir_attrs(where_predicate.hir_id)
             .iter()
             .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym)))
             .map(|attr| attr.span())
@@ -2814,7 +2813,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
 }
 
 fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
-    let attrs = tcx.hir().attrs(item.hir_id());
+    let attrs = tcx.hir_attrs(item.hir_id());
 
     for attr in attrs {
         if attr.has_name(sym::inline) {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 7a14a7a5db2..7029c60c343 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -361,7 +361,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
                 && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
                 && let TyKind::Path(hir::QPath::Resolved(_, path)) =
-                    self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
+                    self.tcx.hir_expect_item(local_impl_of).expect_impl().self_ty.kind
                 && let Res::Def(def_kind, did) = path.res
             {
                 match def_kind {
@@ -424,7 +424,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) {
                         if let Some(local_def_id) = impl_def_id.as_local()
                             && let ItemKind::Impl(impl_ref) =
-                                self.tcx.hir().expect_item(local_def_id).kind
+                                self.tcx.hir_expect_item(local_def_id).kind
                         {
                             // skip items
                             // mark dependent traits live
@@ -448,7 +448,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                     for impl_id in self.tcx.all_impls(trait_id) {
                         if let Some(local_impl_id) = impl_id.as_local()
                             && let ItemKind::Impl(impl_ref) =
-                                self.tcx.hir().expect_item(local_impl_id).kind
+                                self.tcx.hir_expect_item(local_impl_id).kind
                         {
                             if !matches!(trait_item.kind, hir::TraitItemKind::Type(..))
                                 && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 323b414cca0..e13d94c1031 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -19,7 +19,7 @@ use rustc_span::{Symbol, sym};
 use crate::errors::DuplicateDiagnosticItemInCrate;
 
 fn observe_item<'tcx>(tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, owner: OwnerId) {
-    let attrs = tcx.hir().attrs(owner.into());
+    let attrs = tcx.hir_attrs(owner.into());
     if let Some(name) = extract(attrs) {
         // insert into our table
         collect_item(tcx, diagnostic_items, name, owner.to_def_id());
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 25e679a8460..d2729876ebb 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -31,7 +31,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
     }
 
     // If the user wants no main function at all, then stop here.
-    if attr::contains_name(tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) {
+    if attr::contains_name(tcx.hir_attrs(CRATE_HIR_ID), sym::no_main) {
         return None;
     }
 
@@ -45,7 +45,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
 }
 
 fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
-    let attrs = ctxt.tcx.hir().attrs(id.hir_id());
+    let attrs = ctxt.tcx.hir_attrs(id.hir_id());
     attr::find_by_name(attrs, sym).map(|attr| attr.span())
 }
 
@@ -61,7 +61,7 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
 
     let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID);
 
-    let attrs = ctxt.tcx.hir().attrs(id.hir_id());
+    let attrs = ctxt.tcx.hir_attrs(id.hir_id());
     let entry_point_type = rustc_ast::entry::entry_point_type(
         attrs,
         at_root,
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 509c2f54775..84b92d49f24 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -60,19 +60,18 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
             .expect("owning item has no entry");
 
         if max != self.hir_ids_seen.len() - 1 {
-            let hir = self.tcx.hir();
             let pretty_owner = self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose();
 
             let missing_items: Vec<_> = (0..=max as u32)
                 .map(|i| ItemLocalId::from_u32(i))
                 .filter(|&local_id| !self.hir_ids_seen.contains(local_id))
-                .map(|local_id| hir.node_to_string(HirId { owner, local_id }))
+                .map(|local_id| self.tcx.hir_id_to_string(HirId { owner, local_id }))
                 .collect();
 
             let seen_items: Vec<_> = self
                 .hir_ids_seen
                 .iter()
-                .map(|local_id| hir.node_to_string(HirId { owner, local_id }))
+                .map(|local_id| self.tcx.hir_id_to_string(HirId { owner, local_id }))
                 .collect();
 
             self.error(|| {
@@ -137,7 +136,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
             self.error(|| {
                 format!(
                     "HirIdValidator: The recorded owner of {} is {} instead of {}",
-                    self.tcx.hir().node_to_string(hir_id),
+                    self.tcx.hir_id_to_string(hir_id),
                     self.tcx.hir_def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
                     self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose()
                 )
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 822804893fe..ed70d9ee91f 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -157,7 +157,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
     if let Some(upvars) = tcx.upvars_mentioned(def_id) {
         for &var_hir_id in upvars.keys() {
-            let var_name = tcx.hir().name(var_hir_id);
+            let var_name = tcx.hir_name(var_hir_id);
             maps.add_variable(Upvar(var_hir_id, var_name));
         }
     }
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 8e59c0b3251..b06f16cc7bd 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -222,7 +222,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
 
                 if let Some(break_expr) = opt_expr {
                     let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id {
-                        match self.tcx.hir().expect_expr(loop_id).kind {
+                        match self.tcx.hir_expect_expr(loop_id).kind {
                             hir::ExprKind::Loop(_, label, source, sp) => {
                                 (Some(sp), label, Some(source))
                             }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index fd465717bf7..599a08bac20 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -291,7 +291,7 @@ impl<'tcx> ReachableContext<'tcx> {
             _ => {
                 bug!(
                     "found unexpected node kind in worklist: {} ({:?})",
-                    self.tcx.hir().node_to_string(self.tcx.local_def_id_to_hir_id(search_item)),
+                    self.tcx.hir_id_to_string(self.tcx.local_def_id_to_hir_id(search_item)),
                     node,
                 );
             }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 0fcf6a80ec4..aea4386295f 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -118,7 +118,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
     ) where
         F: FnOnce(&mut Self),
     {
-        let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id));
+        let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
         debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
 
         let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
@@ -795,7 +795,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
             }) => {
                 let features = self.tcx.features();
                 if features.staged_api() {
-                    let attrs = self.tcx.hir().attrs(item.hir_id());
+                    let attrs = self.tcx.hir_attrs(item.hir_id());
                     let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
 
                     // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
@@ -1034,7 +1034,7 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     }
 
     // If this is a path that isn't a use, we don't need to do anything special
-    if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) {
+    if !matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) {
         return false;
     }
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5e3e8d69b60..f45e8c065b3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -39,7 +39,7 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Ident, Span, Symbol, kw, sym};
+use rustc_span::{Ident, Span, Symbol, sym};
 use tracing::debug;
 use {rustc_attr_parsing as attr, rustc_hir as hir};
 
@@ -492,7 +492,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
     ) {
         // Non-opaque macros cannot make other items more accessible than they already are.
         let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
-        let attrs = self.tcx.hir().attrs(hir_id);
+        let attrs = self.tcx.hir_attrs(hir_id);
 
         if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
             .unwrap_or(Transparency::fallback(md.macro_rules))
@@ -572,7 +572,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             // have normal hygiene, so we can treat them like other items without type
             // privacy and mark them reachable.
             DefKind::Macro(_) => {
-                let item = self.tcx.hir().expect_item(def_id);
+                let item = self.tcx.hir_expect_item(def_id);
                 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
                     if vis.is_accessible_from(module, self.tcx) {
                         self.update(def_id, macro_ev, Level::Reachable);
@@ -596,7 +596,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
 
             DefKind::Struct | DefKind::Union => {
                 // While structs and unions have type privacy, their fields do not.
-                let item = self.tcx.hir().expect_item(def_id);
+                let item = self.tcx.hir_expect_item(def_id);
                 if let hir::ItemKind::Struct(ref struct_def, _)
                 | hir::ItemKind::Union(ref struct_def, _) = item.kind
                 {
@@ -934,8 +934,8 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         }
 
         // definition of the field
-        let ident = Ident::new(kw::Empty, use_ctxt);
-        let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
+        let ident = Ident::new(sym::dummy, use_ctxt);
+        let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id);
         !field.vis.is_accessible_from(def_id, self.tcx)
     }
 
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 9f062b3935f..817aa5b4385 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -153,9 +153,13 @@ resolve_extern_crate_self_requires_renaming =
     `extern crate self;` requires renaming
     .suggestion = rename the `self` crate to be able to import it
 
+resolve_forward_declared_generic_in_const_param_ty =
+    const parameter types cannot reference parameters before they are declared
+    .label = const parameter type cannot reference `{$param}` before it is declared
+
 resolve_forward_declared_generic_param =
-    generic parameters with a default cannot use forward declared identifiers
-    .label = defaulted generic parameters cannot be forward declared
+    generic parameter defaults cannot reference parameters before they are declared
+    .label = cannot reference `{$param}` before it is declared
 
 resolve_found_an_item_configured_out =
     found an item that was configured out
@@ -377,9 +381,11 @@ resolve_self_imports_only_allowed_within_multipart_suggestion =
 resolve_self_imports_only_allowed_within_suggestion =
     consider importing the module directly
 
+resolve_self_in_const_generic_ty =
+    cannot use `Self` in const parameter type
+
 resolve_self_in_generic_param_default =
     generic parameters cannot use `Self` in their defaults
-    .label = `Self` in generic parameter default
 
 resolve_similarly_named_defined_here =
     similarly named {$candidate_descr} `{$candidate}` defined here
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e3405c89b79..41f4254eede 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -42,10 +42,10 @@ use crate::imports::{Import, ImportKind};
 use crate::late::{PatternSource, Rib};
 use crate::{
     AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize,
-    HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, ModuleKind,
-    ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError,
-    ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError,
-    errors as errs, path_names_to_string,
+    ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module,
+    ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
+    PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
+    VisResolutionError, errors as errs, path_names_to_string,
 };
 
 type Res = def::Res<ast::NodeId>;
@@ -887,9 +887,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 participle,
                 name,
             }),
-            ResolutionError::ForwardDeclaredGenericParam => {
-                self.dcx().create_err(errs::ForwardDeclaredGenericParam { span })
-            }
+            ResolutionError::ForwardDeclaredGenericParam(param, reason) => match reason {
+                ForwardGenericParamBanReason::Default => {
+                    self.dcx().create_err(errs::ForwardDeclaredGenericParam { param, span })
+                }
+                ForwardGenericParamBanReason::ConstParamTy => self
+                    .dcx()
+                    .create_err(errs::ForwardDeclaredGenericInConstParamTy { param, span }),
+            },
             ResolutionError::ParamInTyOfConstParam { name } => {
                 self.dcx().create_err(errs::ParamInTyOfConstParam { span, name })
             }
@@ -908,9 +913,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
                 .dcx()
                 .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
-            ResolutionError::SelfInGenericParamDefault => {
-                self.dcx().create_err(errs::SelfInGenericParamDefault { span })
-            }
+            ResolutionError::ForwardDeclaredSelf(reason) => match reason {
+                ForwardGenericParamBanReason::Default => {
+                    self.dcx().create_err(errs::SelfInGenericParamDefault { span })
+                }
+                ForwardGenericParamBanReason::ConstParamTy => {
+                    self.dcx().create_err(errs::SelfInConstGenericTy { span })
+                }
+            },
             ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
                 let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
                     match suggestion {
@@ -2266,7 +2276,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     && !first.ident.is_path_segment_keyword() =>
             {
                 // Insert a placeholder that's later replaced by `self`/`super`/etc.
-                path.insert(0, Segment::from_ident(Ident::empty()));
+                path.insert(0, Segment::from_ident(Ident::dummy()));
             }
             _ => return None,
         }
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index b5d3e5ea776..2ae6892bc93 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -338,6 +338,16 @@ pub(crate) struct ForwardDeclaredGenericParam {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
+    pub(crate) param: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_forward_declared_generic_in_const_param_ty)]
+pub(crate) struct ForwardDeclaredGenericInConstParamTy {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) param: Symbol,
 }
 
 #[derive(Diagnostic)]
@@ -353,7 +363,13 @@ pub(crate) struct ParamInTyOfConstParam {
 #[diag(resolve_self_in_generic_param_default, code = E0735)]
 pub(crate) struct SelfInGenericParamDefault {
     #[primary_span]
-    #[label]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_self_in_const_generic_ty)]
+pub(crate) struct SelfInConstGenericTy {
+    #[primary_span]
     pub(crate) span: Span,
 }
 
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index d9776be4dd0..5f0a2a597e9 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1117,13 +1117,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         debug!("validate_res_from_ribs({:?})", res);
         let ribs = &all_ribs[rib_index + 1..];
 
-        // An invalid forward use of a generic parameter from a previous default.
-        if let RibKind::ForwardGenericParamBan = all_ribs[rib_index].kind {
+        // An invalid forward use of a generic parameter from a previous default
+        // or in a const param ty.
+        if let RibKind::ForwardGenericParamBan(reason) = all_ribs[rib_index].kind {
             if let Some(span) = finalize {
                 let res_error = if rib_ident.name == kw::SelfUpper {
-                    ResolutionError::SelfInGenericParamDefault
+                    ResolutionError::ForwardDeclaredSelf(reason)
                 } else {
-                    ResolutionError::ForwardDeclaredGenericParam
+                    ResolutionError::ForwardDeclaredGenericParam(rib_ident.name, reason)
                 };
                 self.report_error(span, res_error);
             }
@@ -1131,17 +1132,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             return Res::Err;
         }
 
-        if let RibKind::ConstParamTy = all_ribs[rib_index].kind {
-            if let Some(span) = finalize {
-                self.report_error(
-                    span,
-                    ResolutionError::ParamInTyOfConstParam { name: rib_ident.name },
-                );
-            }
-            assert_eq!(res, Res::Err);
-            return Res::Err;
-        }
-
         match res {
             Res::Local(_) => {
                 use ResolutionError::*;
@@ -1153,7 +1143,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         | RibKind::FnOrCoroutine
                         | RibKind::Module(..)
                         | RibKind::MacroDefinition(..)
-                        | RibKind::ForwardGenericParamBan => {
+                        | RibKind::ForwardGenericParamBan(_) => {
                             // Nothing to do. Continue.
                         }
                         RibKind::Item(..) | RibKind::AssocItem => {
@@ -1247,12 +1237,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         | RibKind::MacroDefinition(..)
                         | RibKind::InlineAsmSym
                         | RibKind::AssocItem
-                        | RibKind::ConstParamTy
-                        | RibKind::ForwardGenericParamBan => {
+                        | RibKind::ForwardGenericParamBan(_) => {
                             // Nothing to do. Continue.
                             continue;
                         }
 
+                        RibKind::ConstParamTy => {
+                            if !self.tcx.features().generic_const_parameter_types() {
+                                if let Some(span) = finalize {
+                                    self.report_error(
+                                        span,
+                                        ResolutionError::ParamInTyOfConstParam {
+                                            name: rib_ident.name,
+                                        },
+                                    );
+                                }
+                                return Res::Err;
+                            } else {
+                                continue;
+                            }
+                        }
+
                         RibKind::ConstantItem(trivial, _) => {
                             if let ConstantHasGenerics::No(cause) = trivial {
                                 // HACK(min_const_generics): If we encounter `Self` in an anonymous
@@ -1325,8 +1330,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         | RibKind::MacroDefinition(..)
                         | RibKind::InlineAsmSym
                         | RibKind::AssocItem
-                        | RibKind::ConstParamTy
-                        | RibKind::ForwardGenericParamBan => continue,
+                        | RibKind::ForwardGenericParamBan(_) => continue,
+
+                        RibKind::ConstParamTy => {
+                            if !self.tcx.features().generic_const_parameter_types() {
+                                if let Some(span) = finalize {
+                                    self.report_error(
+                                        span,
+                                        ResolutionError::ParamInTyOfConstParam {
+                                            name: rib_ident.name,
+                                        },
+                                    );
+                                }
+                                return Res::Err;
+                            } else {
+                                continue;
+                            }
+                        }
 
                         RibKind::ConstantItem(trivial, _) => {
                             if let ConstantHasGenerics::No(cause) = trivial {
@@ -1377,6 +1397,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             }
             _ => {}
         }
+
         res
     }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 79479986d07..d28988cd74f 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -207,7 +207,7 @@ pub(crate) enum RibKind<'ra> {
     /// All bindings in this rib are generic parameters that can't be used
     /// from the default of a generic parameter because they're not declared
     /// before said generic parameter. Also see the `visit_generics` override.
-    ForwardGenericParamBan,
+    ForwardGenericParamBan(ForwardGenericParamBanReason),
 
     /// We are inside of the type of a const parameter. Can't refer to any
     /// parameters.
@@ -218,6 +218,12 @@ pub(crate) enum RibKind<'ra> {
     InlineAsmSym,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub(crate) enum ForwardGenericParamBanReason {
+    Default,
+    ConstParamTy,
+}
+
 impl RibKind<'_> {
     /// Whether this rib kind contains generic parameters, as opposed to local
     /// variables.
@@ -232,7 +238,7 @@ impl RibKind<'_> {
             RibKind::ConstParamTy
             | RibKind::AssocItem
             | RibKind::Item(..)
-            | RibKind::ForwardGenericParamBan => true,
+            | RibKind::ForwardGenericParamBan(_) => true,
         }
     }
 
@@ -246,7 +252,7 @@ impl RibKind<'_> {
             | RibKind::Item(..)
             | RibKind::ConstantItem(..)
             | RibKind::Module(..)
-            | RibKind::ForwardGenericParamBan
+            | RibKind::ForwardGenericParamBan(_)
             | RibKind::ConstParamTy
             | RibKind::InlineAsmSym => true,
         }
@@ -397,32 +403,37 @@ pub(crate) enum AliasPossibility {
 
 #[derive(Copy, Clone, Debug)]
 pub(crate) enum PathSource<'a> {
-    // Type paths `Path`.
+    /// Type paths `Path`.
     Type,
-    // Trait paths in bounds or impls.
+    /// Trait paths in bounds or impls.
     Trait(AliasPossibility),
-    // Expression paths `path`, with optional parent context.
+    /// Expression paths `path`, with optional parent context.
     Expr(Option<&'a Expr>),
-    // Paths in path patterns `Path`.
+    /// Paths in path patterns `Path`.
     Pat,
-    // Paths in struct expressions and patterns `Path { .. }`.
+    /// Paths in struct expressions and patterns `Path { .. }`.
     Struct,
-    // Paths in tuple struct patterns `Path(..)`.
+    /// Paths in tuple struct patterns `Path(..)`.
     TupleStruct(Span, &'a [Span]),
-    // `m::A::B` in `<T as m::A>::B::C`.
+    /// `m::A::B` in `<T as m::A>::B::C`.
     TraitItem(Namespace),
-    // Paths in delegation item
+    /// Paths in delegation item
     Delegation,
     /// An arg in a `use<'a, N>` precise-capturing bound.
     PreciseCapturingArg(Namespace),
-    // Paths that end with `(..)`, for return type notation.
+    /// Paths that end with `(..)`, for return type notation.
     ReturnTypeNotation,
+    /// Paths from `#[define_opaque]` attributes
+    DefineOpaques,
 }
 
 impl<'a> PathSource<'a> {
     fn namespace(self) -> Namespace {
         match self {
-            PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
+            PathSource::Type
+            | PathSource::Trait(_)
+            | PathSource::Struct
+            | PathSource::DefineOpaques => TypeNS,
             PathSource::Expr(..)
             | PathSource::Pat
             | PathSource::TupleStruct(..)
@@ -443,6 +454,7 @@ impl<'a> PathSource<'a> {
             | PathSource::ReturnTypeNotation => true,
             PathSource::Trait(_)
             | PathSource::TraitItem(..)
+            | PathSource::DefineOpaques
             | PathSource::Delegation
             | PathSource::PreciseCapturingArg(..) => false,
         }
@@ -450,6 +462,7 @@ impl<'a> PathSource<'a> {
 
     fn descr_expected(self) -> &'static str {
         match &self {
+            PathSource::DefineOpaques => "type alias or associated type with opaqaue types",
             PathSource::Type => "type",
             PathSource::Trait(_) => "trait",
             PathSource::Pat => "unit struct, unit variant or constant",
@@ -493,6 +506,19 @@ impl<'a> PathSource<'a> {
 
     pub(crate) fn is_expected(self, res: Res) -> bool {
         match self {
+            PathSource::DefineOpaques => {
+                matches!(
+                    res,
+                    Res::Def(
+                        DefKind::Struct
+                            | DefKind::Union
+                            | DefKind::Enum
+                            | DefKind::TyAlias
+                            | DefKind::AssocTy,
+                        _
+                    ) | Res::SelfTyAlias { .. }
+                )
+            }
             PathSource::Type => matches!(
                 res,
                 Res::Def(
@@ -572,16 +598,16 @@ impl<'a> PathSource<'a> {
         match (self, has_unexpected_resolution) {
             (PathSource::Trait(_), true) => E0404,
             (PathSource::Trait(_), false) => E0405,
-            (PathSource::Type, true) => E0573,
-            (PathSource::Type, false) => E0412,
+            (PathSource::Type | PathSource::DefineOpaques, true) => E0573,
+            (PathSource::Type | PathSource::DefineOpaques, false) => E0412,
             (PathSource::Struct, true) => E0574,
             (PathSource::Struct, false) => E0422,
             (PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423,
             (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
             (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
             (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
-            (PathSource::TraitItem(..), true) | (PathSource::ReturnTypeNotation, true) => E0575,
-            (PathSource::TraitItem(..), false) | (PathSource::ReturnTypeNotation, false) => E0576,
+            (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, true) => E0575,
+            (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, false) => E0576,
             (PathSource::PreciseCapturingArg(..), true) => E0799,
             (PathSource::PreciseCapturingArg(..), false) => E0800,
         }
@@ -1541,8 +1567,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         // provide previous type parameters as they're built. We
         // put all the parameters on the ban list and then remove
         // them one by one as they are processed and become available.
-        let mut forward_ty_ban_rib = Rib::new(RibKind::ForwardGenericParamBan);
-        let mut forward_const_ban_rib = Rib::new(RibKind::ForwardGenericParamBan);
+        let mut forward_ty_ban_rib =
+            Rib::new(RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::Default));
+        let mut forward_const_ban_rib =
+            Rib::new(RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::Default));
         for param in params.iter() {
             match param.kind {
                 GenericParamKind::Type { .. } => {
@@ -1573,16 +1601,24 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
         }
 
+        // NOTE: We use different ribs here not for a technical reason, but just
+        // for better diagnostics.
         let mut forward_ty_ban_rib_const_param_ty = Rib {
             bindings: forward_ty_ban_rib.bindings.clone(),
             patterns_with_skipped_bindings: FxHashMap::default(),
-            kind: RibKind::ConstParamTy,
+            kind: RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::ConstParamTy),
         };
         let mut forward_const_ban_rib_const_param_ty = Rib {
             bindings: forward_const_ban_rib.bindings.clone(),
             patterns_with_skipped_bindings: FxHashMap::default(),
-            kind: RibKind::ConstParamTy,
+            kind: RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::ConstParamTy),
         };
+        // We'll ban these with a `ConstParamTy` rib, so just clear these ribs for better
+        // diagnostics, so we don't mention anything about const param tys having generics at all.
+        if !self.r.tcx.features().generic_const_parameter_types() {
+            forward_ty_ban_rib_const_param_ty.bindings.clear();
+            forward_const_ban_rib_const_param_ty.bindings.clear();
+        }
 
         self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
             for param in params {
@@ -1608,9 +1644,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         // Allow all following defaults to refer to this type parameter.
                         let i = &Ident::with_dummy_span(param.ident.name);
                         forward_ty_ban_rib.bindings.remove(i);
-                        if this.r.tcx.features().generic_const_parameter_types() {
-                            forward_ty_ban_rib_const_param_ty.bindings.remove(i);
-                        }
+                        forward_ty_ban_rib_const_param_ty.bindings.remove(i);
                     }
                     GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
                         // Const parameters can't have param bounds.
@@ -1621,9 +1655,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         if this.r.tcx.features().generic_const_parameter_types() {
                             this.visit_ty(ty)
                         } else {
+                            this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy));
+                            this.ribs[ValueNS].push(Rib::new(RibKind::ConstParamTy));
                             this.with_lifetime_rib(LifetimeRibKind::ConstParamTy, |this| {
                                 this.visit_ty(ty)
                             });
+                            this.ribs[TypeNS].pop().unwrap();
+                            this.ribs[ValueNS].pop().unwrap();
                         }
                         forward_const_ban_rib_const_param_ty = this.ribs[ValueNS].pop().unwrap();
                         forward_ty_ban_rib_const_param_ty = this.ribs[TypeNS].pop().unwrap();
@@ -1642,9 +1680,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         // Allow all following defaults to refer to this const parameter.
                         let i = &Ident::with_dummy_span(param.ident.name);
                         forward_const_ban_rib.bindings.remove(i);
-                        if this.r.tcx.features().generic_const_parameter_types() {
-                            forward_const_ban_rib_const_param_ty.bindings.remove(i);
-                        }
+                        forward_const_ban_rib_const_param_ty.bindings.remove(i);
                     }
                 }
             }
@@ -2006,6 +2042,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 | PathSource::Pat
                 | PathSource::Struct
                 | PathSource::TupleStruct(..)
+                | PathSource::DefineOpaques
                 | PathSource::Delegation => true,
             };
             if inferred {
@@ -2619,7 +2656,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 );
             }
 
-            ItemKind::Fn(box Fn { ref generics, .. }) => {
+            ItemKind::Fn(box Fn { ref generics, ref define_opaque, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
                     RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
@@ -2630,6 +2667,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                     },
                     |this| visit::walk_item(this, item),
                 );
+
+                for (id, path) in define_opaque.iter().flatten() {
+                    self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques);
+                }
             }
 
             ItemKind::Enum(_, ref generics)
@@ -3100,8 +3141,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         },
                     );
                 }
-                AssocItemKind::Fn(box Fn { generics, .. }) => {
+                AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => {
                     walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
+
+                    for (id, path) in define_opaque.iter().flatten() {
+                        self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques);
+                    }
                 }
                 AssocItemKind::Delegation(delegation) => {
                     self.with_generic_param_rib(
@@ -3311,7 +3356,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                     },
                 );
             }
-            AssocItemKind::Fn(box Fn { generics, .. }) => {
+            AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => {
                 debug!("resolve_implementation AssocItemKind::Fn");
                 // We also need a new scope for the impl item type parameters.
                 self.with_generic_param_rib(
@@ -3338,6 +3383,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         visit::walk_assoc_item(this, item, AssocCtxt::Impl)
                     },
                 );
+
+                for (id, path) in define_opaque.iter().flatten() {
+                    self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques);
+                }
             }
             AssocItemKind::Type(box TyAlias { generics, .. }) => {
                 self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty());
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f724ecf76b3..495ce843fcd 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -31,7 +31,10 @@ use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use effective_visibilities::EffectiveVisibilitiesVisitor;
 use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
 use imports::{Import, ImportData, ImportKind, NameResolution};
-use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification};
+use late::{
+    ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource,
+    UnnecessaryQualification,
+};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::expand::StrippedCfgItem;
@@ -272,7 +275,7 @@ enum ResolutionError<'ra> {
         shadowed_binding_span: Span,
     },
     /// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
-    ForwardDeclaredGenericParam,
+    ForwardDeclaredGenericParam(Symbol, ForwardGenericParamBanReason),
     // FIXME(generic_const_parameter_types): This should give custom output specifying it's only
     // problematic to use *forward declared* parameters when the feature is enabled.
     /// ERROR E0770: the type of const parameters must not depend on other generic parameters.
@@ -286,7 +289,7 @@ enum ResolutionError<'ra> {
     /// This error is emitted even with `generic_const_exprs`.
     ParamInEnumDiscriminant { name: Symbol, param_kind: ParamKindInEnumDiscriminant },
     /// Error E0735: generic parameters with a default cannot use `Self`
-    SelfInGenericParamDefault,
+    ForwardDeclaredSelf(ForwardGenericParamBanReason),
     /// Error E0767: use of unreachable label
     UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
     /// Error E0323, E0324, E0325: mismatch between trait item and impl item.
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index acd3b758351..aa1921fc8e7 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -272,7 +272,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         let did = tables[def_id];
         let attrs_iter = if let Some(did) = did.as_local() {
-            tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter()
+            tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)).iter()
         } else {
             tcx.attrs_for_def(did).iter()
         };
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9e7f5047eb3..8a8bec35d81 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -33,6 +33,15 @@ symbols! {
         // Special reserved identifiers used internally for elided lifetimes,
         // unnamed method parameters, crate root module, error recovery etc.
         // Matching predicates: `is_any_keyword`, `is_special`/`is_reserved`
+        //
+        // Notes about `kw::Empty`:
+        // - Its use can blur the lines between "empty symbol" and "no symbol".
+        //   Using `Option<Symbol>` is preferable, where possible, because that
+        //   is unambiguous.
+        // - For dummy symbols that are never used and absolutely must be
+        //   present, it's better to use `sym::dummy` than `kw::Empty`, because
+        //   it's clearer that it's intended as a dummy value, and more likely
+        //   to be detected if it accidentally does get used.
         Empty:              "",
         PathRoot:           "{{root}}",
         DollarCrate:        "$crate",
@@ -779,6 +788,7 @@ symbols! {
         default_method_body_is_const,
         default_type_parameter_fallback,
         default_type_params,
+        define_opaque,
         delayed_bug_from_inside_query,
         deny,
         deprecated,
@@ -833,6 +843,7 @@ symbols! {
         drop_types_in_const,
         dropck_eyepatch,
         dropck_parametricity,
+        dummy: "<!dummy!>", // use this instead of `kw::Empty` for symbols that won't be used
         dummy_cgu_name,
         dylib,
         dyn_compatible_for_dispatch,
@@ -1016,6 +1027,7 @@ symbols! {
         from_residual,
         from_size_align_unchecked,
         from_str_method,
+        from_u16,
         from_usize,
         from_yeet,
         fs_create_dir,
@@ -2303,11 +2315,23 @@ impl Ident {
         Ident::new(name, DUMMY_SP)
     }
 
+    /// This is best avoided, because it blurs the lines between "empty
+    /// identifier" and "no identifier". Using `Option<Ident>` is preferable,
+    /// where possible, because that is unambiguous.
     #[inline]
     pub fn empty() -> Ident {
         Ident::with_dummy_span(kw::Empty)
     }
 
+    // For dummy identifiers that are never used and absolutely must be
+    // present, it's better to use `Ident::dummy` than `Ident::Empty`, because
+    // it's clearer that it's intended as a dummy value, and more likely to be
+    // detected if it accidentally does get used.
+    #[inline]
+    pub fn dummy() -> Ident {
+        Ident::with_dummy_span(sym::dummy)
+    }
+
     /// Maps a string to an identifier with a dummy span.
     pub fn from_str(string: &str) -> Ident {
         Ident::with_dummy_span(Symbol::intern(string))
diff --git a/compiler/rustc_target/src/spec/base/linux_wasm.rs b/compiler/rustc_target/src/spec/base/linux_wasm.rs
new file mode 100644
index 00000000000..a8c137c22a9
--- /dev/null
+++ b/compiler/rustc_target/src/spec/base/linux_wasm.rs
@@ -0,0 +1,159 @@
+//! This target is a confluence of Linux and Wasm models, inheriting most
+//! aspects from their respective base targets
+
+use crate::spec::{
+    Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel,
+    add_link_args, crt_objects, cvs,
+};
+
+pub(crate) fn opts() -> TargetOptions {
+    macro_rules! args {
+        ($prefix:literal) => {
+            &[
+                // By default LLD only gives us one page of stack (64k) which is a
+                // little small. Default to a larger stack closer to other PC platforms
+                // (1MB) and users can always inject their own link-args to override this.
+                concat!($prefix, "-z"),
+                concat!($prefix, "stack-size=1048576"),
+                // By default LLD's memory layout is:
+                //
+                // 1. First, a blank page
+                // 2. Next, all static data
+                // 3. Finally, the main stack (which grows down)
+                //
+                // This has the unfortunate consequence that on stack overflows you
+                // corrupt static data and can cause some exceedingly weird bugs. To
+                // help detect this a little sooner we instead request that the stack is
+                // placed before static data.
+                //
+                // This means that we'll generate slightly larger binaries as references
+                // to static data will take more bytes in the ULEB128 encoding, but
+                // stack overflow will be guaranteed to trap as it underflows instead of
+                // corrupting static data.
+                concat!($prefix, "--stack-first"),
+                // FIXME we probably shouldn't pass this but instead pass an explicit list
+                // of symbols we'll allow to be undefined. We don't currently have a
+                // mechanism of knowing, however, which symbols are intended to be imported
+                // from the environment and which are intended to be imported from other
+                // objects linked elsewhere. This is a coarse approximation but is sure to
+                // hide some bugs and frustrate someone at some point, so we should ideally
+                // work towards a world where we can explicitly list symbols that are
+                // supposed to be imported and have all other symbols generate errors if
+                // they remain undefined.
+                concat!($prefix, "--allow-undefined"),
+                // LLD only implements C++-like demangling, which doesn't match our own
+                // mangling scheme. Tell LLD to not demangle anything and leave it up to
+                // us to demangle these symbols later. Currently rustc does not perform
+                // further demangling, but tools like twiggy and wasm-bindgen are intended
+                // to do so.
+                concat!($prefix, "--no-demangle"),
+            ]
+        };
+    }
+
+    let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
+    add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
+
+    TargetOptions {
+        is_like_wasm: true,
+        families: cvs!["wasm", "unix"],
+        os: "linux".into(),
+        env: "musl".into(),
+
+        // we allow dynamic linking, but only cdylibs. Basically we allow a
+        // final library artifact that exports some symbols (a wasm module) but
+        // we don't allow intermediate `dylib` crate types
+        dynamic_linking: true,
+        only_cdylib: true,
+
+        // relatively self-explanatory!
+        exe_suffix: ".wasm".into(),
+        dll_prefix: "".into(),
+        dll_suffix: ".wasm".into(),
+        eh_frame_header: false,
+
+        max_atomic_width: Some(64),
+
+        // Unwinding doesn't work right now, so the whole target unconditionally
+        // defaults to panic=abort. Note that this is guaranteed to change in
+        // the future once unwinding is implemented. Don't rely on this as we're
+        // basically guaranteed to change it once WebAssembly supports
+        // exceptions.
+        panic_strategy: PanicStrategy::Abort,
+
+        // Symbol visibility takes care of this for the WebAssembly.
+        // Additionally the only known linker, LLD, doesn't support the script
+        // arguments just yet
+        limit_rdylib_exports: false,
+
+        // we use the LLD shipped with the Rust toolchain by default
+        linker: Some("rust-lld".into()),
+        linker_flavor: LinkerFlavor::WasmLld(Cc::No),
+
+        pre_link_args,
+
+        // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
+        //
+        // rust-lang/rust#104137: cannot blindly remove this without putting in
+        // some other way to compensate for lack of `-nostartfiles` in linker
+        // invocation.
+        link_self_contained: LinkSelfContainedDefault::True,
+        pre_link_objects_self_contained: crt_objects::pre_wasi_self_contained(),
+        post_link_objects_self_contained: crt_objects::post_wasi_self_contained(),
+
+        // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
+        // PIC code is implemented this has quite a drastic effect if it stays
+        // at the default, `pic`. In an effort to keep wasm binaries as minimal
+        // as possible we're defaulting to `static` for now, but the hope is
+        // that eventually we can ship a `pic`-compatible standard library which
+        // works with `static` as well (or works with some method of generating
+        // non-relative calls and such later on).
+        relocation_model: RelocModel::Static,
+
+        // When the atomics feature is activated then these two keys matter,
+        // otherwise they're basically ignored by the standard library. In this
+        // mode, however, the `#[thread_local]` attribute works (i.e.
+        // `has_thread_local`) and we need to get it to work by specifying
+        // `local-exec` as that's all that's implemented in LLVM today for wasm.
+        has_thread_local: true,
+        tls_model: TlsModel::LocalExec,
+
+        // Supporting Linux requires multithreading supported by Wasm's thread
+        // proposal
+        singlethread: false,
+
+        // gdb scripts don't work on wasm blobs
+        emit_debug_gdb_scripts: false,
+
+        // There's more discussion of this at
+        // https://bugs.llvm.org/show_bug.cgi?id=52442 but the general result is
+        // that this isn't useful for wasm and has tricky issues with
+        // representation, so this is disabled.
+        generate_arange_section: false,
+
+        // Right now this is a bit of a workaround but we're currently saying that
+        // the target by default has a static crt which we're taking as a signal
+        // for "use the bundled crt". If that's turned off then the system's crt
+        // will be used, but this means that default usage of this target doesn't
+        // need an external compiler but it's still interoperable with an external
+        // compiler if configured correctly.
+        crt_static_default: true,
+        crt_static_respected: true,
+
+        // Allow `+crt-static` to create a "cdylib" output which is just a wasm file
+        // without a main function.
+        crt_static_allows_dylibs: true,
+
+        // Wasm start ignores arguments -- relies on API call from interface.
+        main_needs_argc_argv: false,
+
+        // Wasm toolchains mangle the name of "main" to distinguish between different
+        // signatures.
+        entry_name: "__main_void".into(),
+
+        // Wasm Feature flags for supporting Linux
+        features: "+atomics,+bulk-memory,+mutable-globals,+sign-ext".into(),
+
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs
index 6f88be5d37f..e8fdc871785 100644
--- a/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
@@ -18,6 +18,7 @@ pub(crate) mod linux_gnu;
 pub(crate) mod linux_musl;
 pub(crate) mod linux_ohos;
 pub(crate) mod linux_uclibc;
+pub(crate) mod linux_wasm;
 pub(crate) mod msvc;
 pub(crate) mod netbsd;
 pub(crate) mod nto_qnx;
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 15936c731ea..1887134c575 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1924,6 +1924,7 @@ supported_targets! {
     ("wasm32-wasip1", wasm32_wasip1),
     ("wasm32-wasip2", wasm32_wasip2),
     ("wasm32-wasip1-threads", wasm32_wasip1_threads),
+    ("wasm32-wali-linux-musl", wasm32_wali_linux_musl),
     ("wasm64-unknown-unknown", wasm64_unknown_unknown),
 
     ("thumbv6m-none-eabi", thumbv6m_none_eabi),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
new file mode 100644
index 00000000000..a0eb4a254fc
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
@@ -0,0 +1,29 @@
+//! The `wasm32-wali-linux-musl` target is a wasm32 target compliant with the
+//! [WebAssembly Linux Interface](https://github.com/arjunr2/WALI).
+
+use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
+
+pub(crate) fn target() -> Target {
+    let mut options = base::linux_wasm::opts();
+
+    options
+        .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]);
+    options.add_pre_link_args(
+        LinkerFlavor::WasmLld(Cc::Yes),
+        &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"],
+    );
+
+    Target {
+        llvm_target: "wasm32-wasi".into(),
+        metadata: TargetMetadata {
+            description: Some("WebAssembly Linux Interface with musl-libc".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None,
+        },
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
+        arch: "wasm32".into(),
+        options,
+    }
+}
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index d05466bb484..6d3b6608ea2 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -768,17 +768,15 @@ impl Target {
         }
     }
 
-    pub fn implied_target_features<'a>(
-        &self,
-        base_features: impl Iterator<Item = &'a str>,
-    ) -> FxHashSet<&'a str> {
+    // Note: the returned set includes `base_feature`.
+    pub fn implied_target_features<'a>(&self, base_feature: &'a str) -> FxHashSet<&'a str> {
         let implied_features =
             self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::<FxHashMap<_, _>>();
 
-        // implied target features have their own implied target features, so we traverse the
-        // map until there are no more features to add
+        // Implied target features have their own implied target features, so we traverse the
+        // map until there are no more features to add.
         let mut features = FxHashSet::default();
-        let mut new_features = base_features.collect::<Vec<&str>>();
+        let mut new_features = vec![base_feature];
         while let Some(new_feature) = new_features.pop() {
             if features.insert(new_feature) {
                 if let Some(implied_features) = implied_features.get(&new_feature) {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 42d37418fb8..baf2489b2b8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -509,7 +509,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 hir::MatchSource::TryDesugar(scrut_hir_id),
             ) => {
                 if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
-                    let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
+                    let scrut_expr = self.tcx.hir_expect_expr(scrut_hir_id);
                     let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
                         let arg_expr = args.first().expect("try desugaring call w/out arg");
                         self.typeck_results
@@ -548,7 +548,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }) => match source {
                 hir::MatchSource::TryDesugar(scrut_hir_id) => {
                     if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
-                        let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
+                        let scrut_expr = self.tcx.hir_expect_expr(scrut_hir_id);
                         let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
                             let arg_expr = args.first().expect("try desugaring call w/out arg");
                             self.typeck_results
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index a6d8eb6add7..40958ec1088 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -1351,7 +1351,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             && !has_impl_trait(def_id)
             // FIXME(fn_delegation): In delegation item argument spans are equal to last path
             // segment. This leads to ICE's when emitting `multipart_suggestion`.
-            && tcx.hir().opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none()
+            && tcx.hir_opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none()
         {
             let successor =
                 method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 514615735a5..5583deda99a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -395,11 +395,28 @@ impl<T> Trait<T> for X {
                             let sp = tcx
                                 .def_ident_span(body_owner_def_id)
                                 .unwrap_or_else(|| tcx.def_span(body_owner_def_id));
-                            diag.span_note(
-                                sp,
-                                "this item must have the opaque type in its signature in order to \
-                                 be able to register hidden types",
-                            );
+                            let mut alias_def_id = opaque_ty.def_id;
+                            while let DefKind::OpaqueTy = tcx.def_kind(alias_def_id) {
+                                alias_def_id = tcx.parent(alias_def_id);
+                            }
+                            let opaque_path = tcx.def_path_str(alias_def_id);
+                            // FIXME(type_alias_impl_trait): make this a structured suggestion
+                            match tcx.opaque_ty_origin(opaque_ty.def_id) {
+                                rustc_hir::OpaqueTyOrigin::FnReturn { .. } => {}
+                                rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
+                                rustc_hir::OpaqueTyOrigin::TyAlias {
+                                    in_assoc_ty: false, ..
+                                } => {
+                                    diag.span_note(
+                                        sp,
+                                        format!("this item must have a `#[define_opaque({opaque_path})]` \
+                                        attribute to be able to define hidden types"),
+                                    );
+                                }
+                                rustc_hir::OpaqueTyOrigin::TyAlias {
+                                    in_assoc_ty: true, ..
+                                } => {}
+                            }
                         }
                         // If two if arms can be coerced to a trait object, provide a structured
                         // suggestion.
@@ -726,7 +743,7 @@ fn foo(&self) -> Self::T { String::new() }
         if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
             let opaque_local_def_id = def_id.as_local();
             let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
-                tcx.hir().expect_opaque_ty(opaque_local_def_id)
+                tcx.hir_expect_opaque_ty(opaque_local_def_id)
             } else {
                 return false;
             };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index fecb38ab597..c7f0a88f951 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -1023,7 +1023,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 format!(" for lifetime parameter `{name}`")
             }
             infer::UpvarRegion(ref upvar_id, _) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
+                let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id);
                 format!(" for capture of `{var_name}` by closure")
             }
             infer::Nll(..) => bug!("NLL variable found in lexical phase"),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index a7e68e6419d..cdbb92f4c7b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -778,8 +778,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let exp_local_id = exp_def_id.as_local()?;
 
                 match (
-                    &self.tcx.hir().expect_opaque_ty(last_local_id),
-                    &self.tcx.hir().expect_opaque_ty(exp_local_id),
+                    &self.tcx.hir_expect_opaque_ty(last_local_id),
+                    &self.tcx.hir_expect_opaque_ty(exp_local_id),
                 ) {
                     (
                         hir::OpaqueTy { bounds: last_bounds, .. },
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index ad46a15a5ac..4f89f3c2b49 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -22,7 +22,6 @@ use rustc_hir::{
     expr_needs_parens, is_range_literal,
 };
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};
-use rustc_middle::hir::map;
 use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::{
@@ -93,7 +92,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> {
     fn get_from_await_ty<F>(
         &self,
         visitor: AwaitsVisitor,
-        hir: map::Map<'tcx>,
+        tcx: TyCtxt<'tcx>,
         ty_matches: F,
     ) -> Option<Span>
     where
@@ -102,7 +101,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> {
         visitor
             .awaits
             .into_iter()
-            .map(|id| hir.expect_expr(id))
+            .map(|id| tcx.hir_expect_expr(id))
             .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr))))
             .map(|expr| expr.span)
     }
@@ -2180,8 +2179,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err: &mut Diag<'_, G>,
         obligation: &PredicateObligation<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
-
         // Attempt to detect an async-await error by looking at the obligation causes, looking
         // for a coroutine to be present.
         //
@@ -2350,7 +2347,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let mut interior_or_upvar_span = None;
 
-        let from_awaited_ty = coroutine_data.get_from_await_ty(visitor, hir, ty_matches);
+        let from_awaited_ty = coroutine_data.get_from_await_ty(visitor, self.tcx, ty_matches);
         debug!(?from_awaited_ty);
 
         // Avoid disclosing internal information to downstream crates.
@@ -2428,7 +2425,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // Special case the primary error message when send or sync is the trait that was
         // not implemented.
-        let hir = self.tcx.hir();
         let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
             self.tcx.get_diagnostic_name(trait_pred.def_id())
         {
@@ -2455,7 +2451,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             .parent(coroutine_did)
                             .as_local()
                             .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
-                            .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
+                            .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id))
                             .map(|name| {
                                 format!("future returned by `{name}` is not {trait_name}")
                             })?,
@@ -2479,7 +2475,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             .parent(coroutine_did)
                             .as_local()
                             .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
-                            .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
+                            .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id))
                             .map(|name| {
                                 format!("async iterator returned by `{name}` is not {trait_name}")
                             })?,
@@ -2502,7 +2498,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 .parent(coroutine_did)
                                 .as_local()
                                 .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did))
-                                .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
+                                .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id))
                                 .map(|name| {
                                     format!("iterator returned by `{name}` is not {trait_name}")
                                 })?
@@ -3569,7 +3565,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
                 let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info {
                     let expr_ty = tcx.short_string(expr_ty, err.long_ty_path());
-                    let expr = tcx.hir().expect_expr(hir_id);
+                    let expr = tcx.hir_expect_expr(hir_id);
                     (expr_ty, expr)
                 } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
                     && let body = tcx.hir_body(body_id)
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index d4502be6ccf..3fceada2510 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -24,7 +24,9 @@ use super::elaborate;
 use crate::infer::TyCtxtInferExt;
 pub use crate::traits::DynCompatibilityViolation;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::{MethodViolationCode, Obligation, ObligationCause, util};
+use crate::traits::{
+    MethodViolationCode, Obligation, ObligationCause, normalize_param_env_or_error, util,
+};
 
 /// Returns the dyn-compatibility violations that affect HIR ty lowering.
 ///
@@ -579,8 +581,8 @@ fn receiver_is_dispatchable<'tcx>(
     let unsized_receiver_ty =
         receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
 
-    // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
-    // `U: ?Sized` is already implied here
+    // create a modified param env, with `Self: Unsize<U>` and `U: Trait` (and all of
+    // its supertraits) added to caller bounds. `U: ?Sized` is already implied here.
     let param_env = {
         let param_env = tcx.param_env(method.def_id);
 
@@ -598,10 +600,13 @@ fn receiver_is_dispatchable<'tcx>(
             ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx)
         };
 
-        let caller_bounds =
-            param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]);
-
-        ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds))
+        normalize_param_env_or_error(
+            tcx,
+            ty::ParamEnv::new(tcx.mk_clauses_from_iter(
+                param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]),
+            )),
+            ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
+        )
     };
 
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0a54b8468fe..e1adabbeaa6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2231,15 +2231,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 }
             }
 
-            // `Copy` and `Clone` are automatically implemented for an anonymous adt
-            // if all of its fields are `Copy` and `Clone`
-            ty::Adt(adt, args) if adt.is_anonymous() => {
-                // (*) binder moved here
-                Where(obligation.predicate.rebind(
-                    adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(),
-                ))
-            }
-
             ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
                 // Fallback to whatever user-defined impls exist in this case.
                 None
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 4c7a57f2931..7e96b64408c 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2024"
 # tidy-alphabetical-start
 itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index c84055f5b84..b7684e85d41 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -21,7 +21,7 @@ pub(crate) fn provide(providers: &mut Providers) {
 }
 
 fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
-    let item = tcx.hir().expect_item(def_id);
+    let item = tcx.hir_expect_item(def_id);
     match item.kind {
         hir::ItemKind::Trait(.., trait_item_refs) => {
             // We collect RPITITs for each trait method's return type and create a
@@ -96,7 +96,7 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId>
 fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
     let id = tcx.local_def_id_to_hir_id(def_id);
     let parent_def_id = tcx.hir_get_parent_item(id);
-    let parent_item = tcx.hir().expect_item(parent_def_id.def_id);
+    let parent_item = tcx.hir_expect_item(parent_def_id.def_id);
     match parent_item.kind {
         hir::ItemKind::Impl(impl_) => {
             if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id)
@@ -201,7 +201,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
 
             let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
 
-            if let Some(output) = tcx.hir().get_fn_output(fn_def_id) {
+            if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
                 visitor.visit_fn_ret_ty(output);
 
                 tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 6205578bf74..aeaa83c77b5 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -161,7 +161,7 @@ fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Spa
 }
 
 fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> {
-    let item = tcx.hir().expect_item(def_id);
+    let item = tcx.hir_expect_item(def_id);
     if let hir::ItemKind::Impl(impl_) = item.kind {
         let trait_args = impl_
             .of_trait
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 5a4bb2c95da..7334beb52c9 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -220,6 +220,34 @@ fn layout_of_uncached<'tcx>(
                             .try_to_bits(tcx, cx.typing_env)
                             .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
 
+                        // FIXME(pattern_types): create implied bounds from pattern types in signatures
+                        // that require that the range end is >= the range start so that we can't hit
+                        // this error anymore without first having hit a trait solver error.
+                        // Very fuzzy on the details here, but pattern types are an internal impl detail,
+                        // so we can just go with this for now
+                        if scalar.is_signed() {
+                            let range = scalar.valid_range_mut();
+                            let start = layout.size.sign_extend(range.start);
+                            let end = layout.size.sign_extend(range.end);
+                            if end < start {
+                                let guar = tcx.dcx().err(format!(
+                                    "pattern type ranges cannot wrap: {start}..={end}"
+                                ));
+
+                                return Err(error(cx, LayoutError::ReferencesError(guar)));
+                            }
+                        } else {
+                            let range = scalar.valid_range_mut();
+                            if range.end < range.start {
+                                let guar = tcx.dcx().err(format!(
+                                    "pattern type ranges cannot wrap: {}..={}",
+                                    range.start, range.end
+                                ));
+
+                                return Err(error(cx, LayoutError::ReferencesError(guar)));
+                            }
+                        };
+
                         let niche = Niche {
                             offset: Size::ZERO,
                             value: scalar.primitive(),
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 98881905bcf..3aad97d86cc 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{CRATE_HIR_ID, intravisit};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
@@ -30,14 +30,21 @@ enum CollectionMode {
     /// For impl trait in assoc types we only permit collecting them from
     /// associated types of the same impl block.
     ImplTraitInAssocTypes,
-    TypeAliasImplTraitTransition,
+    /// When collecting for an explicit `#[define_opaque]` attribute, find all TAITs
+    Taits,
+    /// The default case, only collect RPITs and AsyncFn return types, as these are
+    /// always defined by the current item.
+    RpitAndAsyncFnOnly,
 }
 
 impl<'tcx> OpaqueTypeCollector<'tcx> {
     fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self {
-        let mode = match tcx.def_kind(tcx.local_parent(item)) {
-            DefKind::Impl { of_trait: true } => CollectionMode::ImplTraitInAssocTypes,
-            _ => CollectionMode::TypeAliasImplTraitTransition,
+        let mode = match tcx.def_kind(item) {
+            DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => {
+                CollectionMode::ImplTraitInAssocTypes
+            }
+            DefKind::TyAlias => CollectionMode::Taits,
+            _ => CollectionMode::RpitAndAsyncFnOnly,
         };
         Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None, mode }
     }
@@ -73,40 +80,6 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         }
     }
 
-    /// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `self.item`.
-    ///
-    /// Example:
-    /// ```ignore UNSOLVED (is this a bug?)
-    /// # #![feature(type_alias_impl_trait)]
-    /// pub mod foo {
-    ///     pub mod bar {
-    ///         pub trait Bar { /* ... */ }
-    ///         pub type Baz = impl Bar;
-    ///
-    ///         # impl Bar for () {}
-    ///         fn f1() -> Baz { /* ... */ }
-    ///     }
-    ///     fn f2() -> bar::Baz { /* ... */ }
-    /// }
-    /// ```
-    ///
-    /// and `opaque_def_id` is the `DefId` of the definition of the opaque type `Baz`.
-    /// For the above example, this function returns `true` for `f1` and `false` for `f2`.
-    #[instrument(level = "trace", skip(self), ret)]
-    fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool {
-        let mut hir_id = self.tcx.local_def_id_to_hir_id(self.item);
-        let opaque_hir_id = self.tcx.local_def_id_to_hir_id(opaque_def_id);
-
-        // Named opaque types can be defined by any siblings or children of siblings.
-        let scope = self.tcx.hir_get_defining_scope(opaque_hir_id);
-        // We walk up the node tree until we hit the root or the scope of the opaque type.
-        while hir_id != scope && hir_id != CRATE_HIR_ID {
-            hir_id = self.tcx.hir_get_parent_item(hir_id).into();
-        }
-        // Syntactically, we are allowed to define the concrete type if:
-        hir_id == scope
-    }
-
     #[instrument(level = "trace", skip(self))]
     fn collect_taits_declared_in_body(&mut self) {
         let body = self.tcx.hir_body_owned_by(self.item).value;
@@ -139,18 +112,31 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         }
 
         // TAITs outside their defining scopes are ignored.
-        let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local());
-        trace!(?origin);
-        match origin {
+        match self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()) {
             rustc_hir::OpaqueTyOrigin::FnReturn { .. }
             | rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
-            rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
-                if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
-                    return;
+            rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => match self.mode {
+                // If we are collecting opaques in an assoc method, we are only looking at assoc types
+                // mentioned in the assoc method and only at opaques defined in there. We do not
+                // want to collect TAITs
+                CollectionMode::ImplTraitInAssocTypes => {
+                    if !in_assoc_ty {
+                        return;
+                    }
                 }
-            }
+                // If we are collecting opaques referenced from a `define_opaque` attribute, we
+                // do not want to look at opaques defined in associated types. Those can only be
+                // defined by methods on the same impl.
+                CollectionMode::Taits => {
+                    if in_assoc_ty {
+                        return;
+                    }
+                }
+                CollectionMode::RpitAndAsyncFnOnly => return,
+            },
         }
 
+        trace!(?alias_ty, "adding");
         self.opaques.push(alias_ty.def_id.expect_local());
 
         let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
@@ -192,6 +178,32 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
             }
         }
     }
+
+    /// Checks the `#[define_opaque]` attributes on items and collectes opaques to define
+    /// from the referenced types.
+    #[instrument(level = "trace", skip(self))]
+    fn collect_taits_from_defines_attr(&mut self) {
+        let hir_id = self.tcx.local_def_id_to_hir_id(self.item);
+        if !hir_id.is_owner() {
+            return;
+        }
+        let Some(defines) = self.tcx.hir_attr_map(hir_id.owner).define_opaque else {
+            return;
+        };
+        for &(span, define) in defines {
+            trace!(?define);
+            let mode = std::mem::replace(&mut self.mode, CollectionMode::Taits);
+            let n = self.opaques.len();
+            super::sig_types::walk_types(self.tcx, define, self);
+            if n == self.opaques.len() {
+                self.tcx.dcx().span_err(span, "item does not contain any opaque types");
+            }
+            self.mode = mode;
+        }
+        // Allow using `#[define_opaque]` on assoc methods and type aliases to override the default collection mode in
+        // case it was capturing too much.
+        self.mode = CollectionMode::RpitAndAsyncFnOnly;
+    }
 }
 
 impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
@@ -210,6 +222,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                 self.visit_opaque_ty(alias_ty);
             }
             // Skips type aliases, as they are meant to be transparent.
+            // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly?
             ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
                 self.tcx
                     .type_of(alias_ty.def_id)
@@ -283,28 +296,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                     self.visit_opaque_ty(alias_ty);
                 }
             }
-            ty::Adt(def, _) if def.did().is_local() => {
-                if let CollectionMode::ImplTraitInAssocTypes = self.mode {
-                    return;
-                }
-                if !self.seen.insert(def.did().expect_local()) {
-                    return;
-                }
-                for variant in def.variants().iter() {
-                    for field in variant.fields.iter() {
-                        // Don't use the `ty::Adt` args, we either
-                        // * found the opaque in the args
-                        // * will find the opaque in the uninstantiated fields
-                        // The only other situation that can occur is that after instantiating,
-                        // some projection resolves to an opaque that we would have otherwise
-                        // not found. While we could instantiate and walk those, that would mean we
-                        // would have to walk all generic parameters of an Adt, which can quickly
-                        // degenerate into looking at an exponential number of types.
-                        let ty = self.tcx.type_of(field.did).instantiate_identity();
-                        self.visit_spanned(self.tcx.def_span(field.did), ty);
-                    }
-                }
-            }
             _ => trace!(kind=?t.kind()),
         }
     }
@@ -317,7 +308,9 @@ fn opaque_types_defined_by<'tcx>(
     let kind = tcx.def_kind(item);
     trace!(?kind);
     let mut collector = OpaqueTypeCollector::new(tcx, item);
+    collector.collect_taits_from_defines_attr();
     super::sig_types::walk_types(tcx, item, &mut collector);
+
     match kind {
         DefKind::AssocFn
         | DefKind::Fn
@@ -350,8 +343,7 @@ fn opaque_types_defined_by<'tcx>(
         | DefKind::GlobalAsm
         | DefKind::Impl { .. }
         | DefKind::SyntheticCoroutineBody => {}
-        // Closures and coroutines are type checked with their parent, so we need to allow all
-        // opaques from the closure signature *and* from the parent body.
+        // Closures and coroutines are type checked with their parent
         DefKind::Closure | DefKind::InlineConst => {
             collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item)));
         }
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 7b2593b96e3..4adf7157926 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -33,6 +33,3 @@ nightly = [
     "rustc_index/nightly",
     "rustc_ast_ir/nightly",
 ]
-
-[lints.rust]
-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] }