about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs114
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs30
-rw-r--r--compiler/rustc_attr/messages.ftl2
-rw-r--r--compiler/rustc_attr/src/builtin.rs57
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs10
-rw-r--r--compiler/rustc_borrowck/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs8
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/types.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs6
-rw-r--r--compiler/rustc_data_structures/src/stack.rs4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0607.md10
-rw-r--r--compiler/rustc_expand/src/config.rs8
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs41
-rw-r--r--compiler/rustc_hir/src/intravisit.rs25
-rw-r--r--compiler/rustc_hir/src/target.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs34
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs50
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs79
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs129
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs68
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/variance/dump.rs13
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs15
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl8
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs26
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs91
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs36
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs13
-rw-r--r--compiler/rustc_infer/src/infer/relate/glb.rs159
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs302
-rw-r--r--compiler/rustc_infer/src/infer/relate/lub.rs158
-rw-r--r--compiler/rustc_infer/src/infer/relate/mod.rs2
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/async_fn_in_trait.rs7
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs6
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/lints.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs16
-rw-r--r--compiler/rustc_lint/src/types.rs23
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs20
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs9
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs37
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs12
-rw-r--r--compiler/rustc_middle/src/middle/resolve_bound_vars.rs10
-rw-r--r--compiler/rustc_middle/src/query/mod.rs26
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs22
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs10
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs14
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs3
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs6
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs8
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs16
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs8
-rw-r--r--compiler/rustc_parse/src/lib.rs4
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs8
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs10
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs1
-rw-r--r--compiler/rustc_passes/src/reachable.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs73
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs8
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs2
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs2
-rw-r--r--compiler/rustc_session/src/cstore.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs2
-rw-r--r--compiler/rustc_target/src/abi/mod.rs2
-rw-r--r--compiler/rustc_target/src/spec/base/avr_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs38
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs9
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs13
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs34
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs18
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs5
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs14
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs18
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs4
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs40
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs2
-rw-r--r--compiler/stable_mir/src/mir/body.rs6
-rw-r--r--compiler/stable_mir/src/mir/visit.rs4
145 files changed, 1436 insertions, 1224 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 124d0acfa49..338d50cb394 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -527,6 +527,16 @@ impl NestedMetaItem {
         }
     }
 
+    /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's
+    /// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
+    pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> {
+        match self {
+            NestedMetaItem::MetaItem(_item) => Some(self),
+            NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
+            _ => None,
+        }
+    }
+
     /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
     pub fn meta_item(&self) -> Option<&MetaItem> {
         match self {
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index e77c0fb3a3e..6289966561f 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -226,6 +226,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
+    fn visit_opaque_ty(&mut self, opaq: &'hir OpaqueTy<'hir>) {
+        self.insert(opaq.span, opaq.hir_id, Node::OpaqueTy(opaq));
+
+        self.with_parent(opaq.hir_id, |this| {
+            intravisit::walk_opaque_ty(this, opaq);
+        });
+    }
+
     fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
         // FIXME: use real span?
         self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7bb3b2fa290..1273b50dff8 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -286,7 +286,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                 parent: this.local_def_id(id),
                                 in_assoc_ty: false,
                             },
-                            fn_kind: None,
                         }),
                     },
                 );
@@ -983,7 +982,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                     parent: this.local_def_id(i.id),
                                     in_assoc_ty: true,
                                 },
-                                fn_kind: None,
                             });
                             hir::ImplItemKind::Type(ty)
                         }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c6cb7aa7dd5..b26797f4203 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -288,12 +288,7 @@ enum ImplTraitContext {
     /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
     /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
     ///
-    OpaqueTy {
-        origin: hir::OpaqueTyOrigin,
-        /// Only used to change the lifetime capture rules, since
-        /// RPITIT captures all in scope, RPIT does not.
-        fn_kind: Option<FnDeclKind>,
-    },
+    OpaqueTy { origin: hir::OpaqueTyOrigin },
     /// `impl Trait` is unstably accepted in this position.
     FeatureGated(ImplTraitPosition, Symbol),
     /// `impl Trait` is not accepted in this position.
@@ -1404,14 +1399,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             TyKind::ImplTrait(def_node_id, bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
-                        span,
-                        origin,
-                        *def_node_id,
-                        bounds,
-                        fn_kind,
-                        itctx,
-                    ),
+                    ImplTraitContext::OpaqueTy { origin } => {
+                        self.lower_opaque_impl_trait(span, origin, *def_node_id, bounds, itctx)
+                    }
                     ImplTraitContext::Universal => {
                         if let Some(span) = bounds.iter().find_map(|bound| match *bound {
                             ast::GenericBound::Use(_, span) => Some(span),
@@ -1513,7 +1503,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
-        fn_kind: Option<FnDeclKind>,
         itctx: ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
@@ -1555,11 +1544,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         .map(|(ident, id, _)| Lifetime { id, ident })
                         .collect()
                 }
-                hir::OpaqueTyOrigin::FnReturn(..) => {
-                    if matches!(
-                        fn_kind.expect("expected RPITs to be lowered with a FnKind"),
-                        FnDeclKind::Impl | FnDeclKind::Trait
-                    ) || self.tcx.features().lifetime_capture_rules_2024
+                hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => {
+                    if in_trait_or_impl.is_some()
+                        || self.tcx.features().lifetime_capture_rules_2024
                         || span.at_least_rust_2024()
                     {
                         // return-position impl trait in trait was decided to capture all
@@ -1576,16 +1563,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
                     }
                 }
-                hir::OpaqueTyOrigin::AsyncFn(..) => {
+                hir::OpaqueTyOrigin::AsyncFn { .. } => {
                     unreachable!("should be using `lower_async_fn_ret_ty`")
                 }
             }
         };
         debug!(?captured_lifetimes_to_duplicate);
 
-        match fn_kind {
-            // Deny `use<>` on RPITIT in trait/trait-impl for now.
-            Some(FnDeclKind::Trait | FnDeclKind::Impl) => {
+        // Feature gate for RPITIT + use<..>
+        match origin {
+            rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
                 if let Some(span) = bounds.iter().find_map(|bound| match *bound {
                     ast::GenericBound::Use(_, span) => Some(span),
                     _ => None,
@@ -1593,20 +1580,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span });
                 }
             }
-            None
-            | Some(
-                FnDeclKind::Fn
-                | FnDeclKind::Inherent
-                | FnDeclKind::ExternFn
-                | FnDeclKind::Closure
-                | FnDeclKind::Pointer,
-            ) => {}
+            _ => {}
         }
 
         self.lower_opaque_inner(
             opaque_ty_node_id,
             origin,
-            matches!(fn_kind, Some(FnDeclKind::Trait)),
             captured_lifetimes_to_duplicate,
             span,
             opaque_ty_span,
@@ -1618,14 +1597,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         opaque_ty_node_id: NodeId,
         origin: hir::OpaqueTyOrigin,
-        in_trait: bool,
         captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
         span: Span,
         opaque_ty_span: Span,
         lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
     ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
-        debug!(?opaque_ty_def_id);
+        let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id);
+        debug!(?opaque_ty_def_id, ?opaque_ty_hir_id);
 
         // Map from captured (old) lifetime to synthetic (new) lifetime.
         // Used to resolve lifetimes in the bounds of the opaque.
@@ -1698,7 +1677,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
 
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+        let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| {
             // Install the remapping from old to new (if any). This makes sure that
             // any lifetimes that would have resolved to the def-id of captured
             // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
@@ -1736,7 +1715,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
             let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
 
-            let opaque_ty_item = hir::OpaqueTy {
+            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+            let opaque_ty_def = hir::OpaqueTy {
+                hir_id: opaque_ty_hir_id,
+                def_id: opaque_ty_def_id,
                 generics: this.arena.alloc(hir::Generics {
                     params: generic_params,
                     predicates: &[],
@@ -1747,20 +1729,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 bounds,
                 origin,
                 lifetime_mapping,
-                in_trait,
-            };
-
-            // Generate an `type Foo = impl Trait;` declaration.
-            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
-            let opaque_ty_item = hir::Item {
-                owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
-                ident: Ident::empty(),
-                kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
-                vis_span: this.lower_span(span.shrink_to_lo()),
                 span: this.lower_span(opaque_ty_span),
             };
-
-            hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
+            this.arena.alloc(opaque_ty_def)
         });
 
         let generic_args = self.arena.alloc_from_iter(
@@ -1773,11 +1744,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited. It's
         // only the lifetime parameters that we must supply.
-        hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            generic_args,
-            in_trait,
-        )
+        hir::TyKind::OpaqueDef(opaque_ty_def, generic_args)
     }
 
     fn lower_precise_capturing_args(
@@ -1864,12 +1831,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             None => match &decl.output {
                 FnRetTy::Ty(ty) => {
                     let itctx = match kind {
-                        FnDeclKind::Fn
-                        | FnDeclKind::Inherent
-                        | FnDeclKind::Trait
-                        | FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
-                            origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
-                            fn_kind: Some(kind),
+                        FnDeclKind::Fn | FnDeclKind::Inherent => ImplTraitContext::OpaqueTy {
+                            origin: hir::OpaqueTyOrigin::FnReturn {
+                                parent: self.local_def_id(fn_node_id),
+                                in_trait_or_impl: None,
+                            },
+                        },
+                        FnDeclKind::Trait => ImplTraitContext::OpaqueTy {
+                            origin: hir::OpaqueTyOrigin::FnReturn {
+                                parent: self.local_def_id(fn_node_id),
+                                in_trait_or_impl: Some(hir::RpitContext::Trait),
+                            },
+                        },
+                        FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
+                            origin: hir::OpaqueTyOrigin::FnReturn {
+                                parent: self.local_def_id(fn_node_id),
+                                in_trait_or_impl: Some(hir::RpitContext::TraitImpl),
+                            },
                         },
                         FnDeclKind::ExternFn => {
                             ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
@@ -1951,10 +1929,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             .map(|(ident, id, _)| Lifetime { id, ident })
             .collect();
 
+        let in_trait_or_impl = match fn_kind {
+            FnDeclKind::Trait => Some(hir::RpitContext::Trait),
+            FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl),
+            FnDeclKind::Fn | FnDeclKind::Inherent => None,
+            FnDeclKind::ExternFn | FnDeclKind::Closure | FnDeclKind::Pointer => unreachable!(),
+        };
+
         let opaque_ty_ref = self.lower_opaque_inner(
             opaque_ty_node_id,
-            hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-            matches!(fn_kind, FnDeclKind::Trait),
+            hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
             captured_lifetimes,
             span,
             opaque_ty_span,
@@ -1964,8 +1948,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     coro,
                     opaque_ty_span,
                     ImplTraitContext::OpaqueTy {
-                        origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
-                        fn_kind: Some(fn_kind),
+                        origin: hir::OpaqueTyOrigin::FnReturn {
+                            parent: fn_def_id,
+                            in_trait_or_impl,
+                        },
                     },
                 );
                 arena_vec![this; bound]
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 229d04f8de2..5bdd9b6eda8 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -63,7 +63,7 @@ impl TraitOrTraitImpl {
 }
 
 struct AstValidator<'a> {
-    session: &'a Session,
+    sess: &'a Session,
     features: &'a Features,
 
     /// The span of the `extern` in an `extern { ... }` block, if any.
@@ -267,7 +267,7 @@ impl<'a> AstValidator<'a> {
     }
 
     fn dcx(&self) -> DiagCtxtHandle<'a> {
-        self.session.dcx()
+        self.sess.dcx()
     }
 
     fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
@@ -359,7 +359,7 @@ impl<'a> AstValidator<'a> {
             in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
             const_context_label: parent_constness,
             remove_const_sugg: (
-                self.session.source_map().span_extend_while_whitespace(span),
+                self.sess.source_map().span_extend_while_whitespace(span),
                 match parent_constness {
                     Some(_) => rustc_errors::Applicability::MachineApplicable,
                     None => rustc_errors::Applicability::MaybeIncorrect,
@@ -472,7 +472,7 @@ impl<'a> AstValidator<'a> {
 
     fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
         if let Defaultness::Default(def_span) = defaultness {
-            let span = self.session.source_map().guess_head_span(span);
+            let span = self.sess.source_map().guess_head_span(span);
             self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
         }
     }
@@ -480,7 +480,7 @@ impl<'a> AstValidator<'a> {
     /// If `sp` ends with a semicolon, returns it as a `Span`
     /// Otherwise, returns `sp.shrink_to_hi()`
     fn ending_semi_or_hi(&self, sp: Span) -> Span {
-        let source_map = self.session.source_map();
+        let source_map = self.sess.source_map();
         let end = source_map.end_point(sp);
 
         if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {
@@ -552,7 +552,7 @@ impl<'a> AstValidator<'a> {
     }
 
     fn current_extern_span(&self) -> Span {
-        self.session.source_map().guess_head_span(self.extern_mod.unwrap())
+        self.sess.source_map().guess_head_span(self.extern_mod.unwrap())
     }
 
     /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
@@ -648,7 +648,7 @@ impl<'a> AstValidator<'a> {
         if ident.name.as_str().is_ascii() {
             return;
         }
-        let span = self.session.source_map().guess_head_span(item_span);
+        let span = self.sess.source_map().guess_head_span(item_span);
         self.dcx().emit_err(errors::NoMangleAscii { span });
     }
 
@@ -753,7 +753,7 @@ impl<'a> AstValidator<'a> {
                     self.dcx().emit_err(errors::PatternFnPointer { span });
                 });
                 if let Extern::Implicit(_) = bfty.ext {
-                    let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
+                    let sig_span = self.sess.source_map().next_point(ty.span.shrink_to_lo());
                     self.maybe_lint_missing_abi(sig_span, ty.id);
                 }
             }
@@ -795,7 +795,7 @@ impl<'a> AstValidator<'a> {
         // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
         // call site which do not have a macro backtrace. See #61963.
         if self
-            .session
+            .sess
             .source_map()
             .span_to_snippet(span)
             .is_ok_and(|snippet| !snippet.starts_with("#["))
@@ -885,7 +885,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
 
 impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_attribute(&mut self, attr: &Attribute) {
-        validate_attr::check_attr(&self.session.psess, attr);
+        validate_attr::check_attr(&self.sess.psess, attr);
     }
 
     fn visit_ty(&mut self, ty: &'a Ty) {
@@ -1192,7 +1192,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 } else if where_clauses.after.has_where_token {
                     self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
                         span: where_clauses.after.span,
-                        help: self.session.is_nightly_build(),
+                        help: self.sess.is_nightly_build(),
                     });
                 }
             }
@@ -1328,7 +1328,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
                         if !self.features.more_maybe_bounds =>
                     {
-                        self.session
+                        self.sess
                             .create_feature_err(
                                 errors::OptionalTraitSupertrait {
                                     span: trait_ref.span,
@@ -1341,7 +1341,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
                         if !self.features.more_maybe_bounds =>
                     {
-                        self.session
+                        self.sess
                             .create_feature_err(
                                 errors::OptionalTraitObject { span: trait_ref.span },
                                 sym::more_maybe_bounds,
@@ -1752,13 +1752,13 @@ fn deny_equality_constraints(
 }
 
 pub fn check_crate(
-    session: &Session,
+    sess: &Session,
     features: &Features,
     krate: &Crate,
     lints: &mut LintBuffer,
 ) -> bool {
     let mut validator = AstValidator {
-        session,
+        sess,
         features,
         extern_mod: None,
         outer_trait_or_trait_impl: None,
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index 5d9ac23ec49..adabf18ca85 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -107,6 +107,8 @@ attr_unknown_version_literal =
 attr_unstable_cfg_target_compact =
     compact `cfg(target(..))` is experimental and subject to change
 
+attr_unsupported_literal_cfg_boolean =
+    literal in `cfg` predicate value must be a boolean
 attr_unsupported_literal_cfg_string =
     literal in `cfg` predicate value must be a string
 attr_unsupported_literal_deprecated_kv_pair =
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 28d73fbe9f3..d6a7dbad12d 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
 use rustc_session::{RustcVersion, Session};
 use rustc_span::Span;
 use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::{Symbol, kw, sym};
 
 use crate::fluent_generated;
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
 pub(crate) enum UnsupportedLiteralReason {
     Generic,
     CfgString,
+    CfgBoolean,
     DeprecatedString,
     DeprecatedKvPair,
 }
@@ -533,7 +534,7 @@ pub struct Condition {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(
-    cfg: &ast::MetaItem,
+    cfg: &ast::NestedMetaItem,
     sess: &Session,
     lint_node_id: NodeId,
     features: Option<&Features>,
@@ -604,12 +605,43 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
 pub fn eval_condition(
-    cfg: &ast::MetaItem,
+    cfg: &ast::NestedMetaItem,
     sess: &Session,
     features: Option<&Features>,
     eval: &mut impl FnMut(Condition) -> bool,
 ) -> bool {
     let dcx = sess.dcx();
+
+    let cfg = match cfg {
+        ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
+        ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
+            if let Some(features) = features {
+                // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
+                // and `true`, and we want to keep the former working without feature gate
+                gate_cfg(
+                    &((
+                        if *b { kw::True } else { kw::False },
+                        sym::cfg_boolean_literals,
+                        |features: &Features| features.cfg_boolean_literals,
+                    )),
+                    cfg.span(),
+                    sess,
+                    features,
+                );
+            }
+            return *b;
+        }
+        _ => {
+            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: cfg.span(),
+                reason: UnsupportedLiteralReason::CfgBoolean,
+                is_bytestr: false,
+                start_point_span: sess.source_map().start_point(cfg.span()),
+            });
+            return false;
+        }
+    };
+
     match &cfg.kind {
         ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
             try_gate_cfg(sym::version, cfg.span, sess, features);
@@ -645,7 +677,7 @@ pub fn eval_condition(
         }
         ast::MetaItemKind::List(mis) => {
             for mi in mis.iter() {
-                if !mi.is_meta_item() {
+                if mi.meta_item_or_bool().is_none() {
                     dcx.emit_err(session_diagnostics::UnsupportedLiteral {
                         span: mi.span(),
                         reason: UnsupportedLiteralReason::Generic,
@@ -663,23 +695,19 @@ pub fn eval_condition(
                     .iter()
                     // We don't use any() here, because we want to evaluate all cfg condition
                     // as eval_condition can (and does) extra checks
-                    .fold(false, |res, mi| {
-                        res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
-                    }),
+                    .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
                 sym::all => mis
                     .iter()
                     // We don't use all() here, because we want to evaluate all cfg condition
                     // as eval_condition can (and does) extra checks
-                    .fold(true, |res, mi| {
-                        res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
-                    }),
+                    .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
                 sym::not => {
                     let [mi] = mis.as_slice() else {
                         dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
                         return false;
                     };
 
-                    !eval_condition(mi.meta_item().unwrap(), sess, features, eval)
+                    !eval_condition(mi, sess, features, eval)
                 }
                 sym::target => {
                     if let Some(features) = features
@@ -700,7 +728,12 @@ pub fn eval_condition(
                             seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
                         }
 
-                        res & eval_condition(&mi, sess, features, eval)
+                        res & eval_condition(
+                            &ast::NestedMetaItem::MetaItem(mi),
+                            sess,
+                            features,
+                            eval,
+                        )
                     })
                 }
                 _ => {
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 959a5a4bba7..626840aa6a3 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
         let mut diag = Diag::new(dcx, level, match self.reason {
             UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
             UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
+            UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
             UnsupportedLiteralReason::DeprecatedString => {
                 fluent::attr_unsupported_literal_deprecated_string
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 2f22e1532c1..1a5f9bdb154 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -830,20 +830,14 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
     ///
     /// [`OpaqueDef`]: hir::TyKind::OpaqueDef
     fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
-        let hir = self.infcx.tcx.hir();
-
-        let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
+        let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else {
             span_bug!(
                 hir_ty.span,
                 "lowered return type of async fn is not OpaqueDef: {:?}",
                 hir_ty
             );
         };
-        let opaque_ty = hir.item(id);
-        if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-            bounds: [hir::GenericBound::Trait(trait_ref, _)],
-            ..
-        }) = opaque_ty.kind
+        if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref, _)], .. } = opaque_ty
             && let Some(segment) = trait_ref.trait_ref.path.segments.last()
             && let Some(args) = segment.args
             && let [constraint] = args.constraints
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index a11eca0b9c7..3b0b3ee1a74 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -5,7 +5,6 @@
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(file_buffered)]
 #![feature(let_chains)]
 #![feature(never_type)]
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 3cf21d4a36b..a16c1931a55 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -329,8 +329,8 @@ fn check_opaque_type_well_formed<'tcx>(
 ) -> Result<Ty<'tcx>, ErrorGuaranteed> {
     // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
     // on stable and we'd break that.
-    let opaque_ty_hir = tcx.hir().expect_item(def_id);
-    let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else {
+    let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
+    let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
         return Ok(definition_ty);
     };
     let param_env = tcx.param_env(def_id);
@@ -503,8 +503,8 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
         let &Self { tcx, def_id, .. } = self;
         let origin = tcx.opaque_type_origin(def_id);
         let parent = match origin {
-            hir::OpaqueTyOrigin::FnReturn(parent)
-            | hir::OpaqueTyOrigin::AsyncFn(parent)
+            hir::OpaqueTyOrigin::FnReturn { parent, .. }
+            | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
             | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
         };
         let param_env = tcx.param_env(parent);
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 0a375c7fae8..b7aef71eb54 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -11,7 +11,7 @@ use crate::BorrowckInferCtxt;
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
 #[instrument(skip(infcx, body, promoted), level = "debug")]
-pub fn renumber_mir<'tcx>(
+pub(crate) fn renumber_mir<'tcx>(
     infcx: &BorrowckInferCtxt<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index fc1600ea4a6..6c86968389a 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -97,7 +97,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
     /// that we computed for the closure. This has the effect of adding new outlives obligations
     /// to existing region variables in `closure_args`.
     #[instrument(skip(self), level = "debug")]
-    pub fn apply_closure_requirements(
+    pub(crate) fn apply_closure_requirements(
         &mut self,
         closure_requirements: &ClosureRegionRequirements<'tcx>,
         closure_def_id: DefId,
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index cf1d5c68ead..940c94b1cfc 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -6,7 +6,6 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::PResult;
 use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
-use rustc_parse::parser::attr::AllowLeadingUnsafe;
 use rustc_span::Span;
 use {rustc_ast as ast, rustc_attr as attr};
 
@@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
     })
 }
 
-fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
+fn parse_cfg<'a>(
+    cx: &ExtCtxt<'a>,
+    span: Span,
+    tts: TokenStream,
+) -> PResult<'a, ast::NestedMetaItem> {
     let mut p = cx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
         return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
     }
 
-    let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
+    let cfg = p.parse_meta_item_inner()?;
 
     let _ = p.eat(&token::Comma);
 
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index ebaa9c69c81..3078288c286 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -168,7 +168,7 @@ fn main() {
 
     foo(I64X2([0, 0]));
 
-    transmute_fat_pointer();
+    transmute_wide_pointer();
 
     rust_call_abi();
 
@@ -192,7 +192,7 @@ type TwoPtrs = i64;
 #[cfg(target_pointer_width = "64")]
 type TwoPtrs = i128;
 
-fn transmute_fat_pointer() -> TwoPtrs {
+fn transmute_wide_pointer() -> TwoPtrs {
     unsafe { transmute::<_, TwoPtrs>("true !") }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 1ce0aacab49..09680622069 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -713,17 +713,17 @@ fn codegen_stmt<'tcx>(
                     let from_ty = operand.layout().ty;
                     let to_ty = fx.monomorphize(to_ty);
 
-                    fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
+                    fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                         ty.builtin_deref(true)
                             .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty))
                     }
 
-                    if is_fat_ptr(fx, from_ty) {
-                        if is_fat_ptr(fx, to_ty) {
-                            // fat-ptr -> fat-ptr
+                    if is_wide_ptr(fx, from_ty) {
+                        if is_wide_ptr(fx, to_ty) {
+                            // wide-ptr -> wide-ptr
                             lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
                         } else {
-                            // fat-ptr -> thin-ptr
+                            // wide-ptr -> thin-ptr
                             let (ptr, _extra) = operand.load_scalar_pair(fx);
                             lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
                         }
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index e78ba5a3415..69a32cc3d43 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>(
     })
 }
 
-/// Is a pointer to this type a fat ptr?
+/// Is a pointer to this type a wide ptr?
 pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
     if ty.is_sized(tcx, ParamEnv::reveal_all()) {
         return false;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs
index a710701e72c..714742aeaff 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs
@@ -139,7 +139,7 @@ impl DebugContext {
 
             pointer_type_id
         } else {
-            // FIXME implement debuginfo for fat pointers
+            // FIXME implement debuginfo for wide pointers
             self.placeholder_for_type(tcx, type_dbg, ptr_type)
         }
     }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index eeab2a5f155..4e1b99fdebf 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -478,7 +478,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: in_elem
@@ -493,7 +493,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: out_elem
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index cb45bbde2c2..5b0d862ae6d 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -207,7 +207,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
         // layout.
         if let Abi::Scalar(ref scalar) = self.abi {
             // Use a different cache for scalars because pointers to DSTs
-            // can be either fat or thin (data pointers of fat pointers).
+            // can be either wide or thin (data pointers of wide pointers).
             if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
                 return ty;
             }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 3d75393bf06..6a29eb5fa04 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -7,7 +7,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
-pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
+pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
 use rustc_middle::{bug, ty};
 use rustc_session::config;
 pub(crate) use rustc_target::abi::call::*;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index b7a6f80956d..15d441a986d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -34,7 +34,7 @@ use super::utils::{
 };
 use crate::common::CodegenCx;
 use crate::debuginfo::metadata::type_map::build_type_with_children;
-use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind};
+use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
 use crate::llvm::debuginfo::{
     DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
     DebugNameTableKind,
@@ -161,7 +161,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
     unique_type_id: UniqueTypeId<'tcx>,
 ) -> DINodeCreationResult<'ll> {
     // The debuginfo generated by this function is only valid if `ptr_type` is really just
-    // a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
+    // a (wide) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
     assert_eq!(
         cx.size_and_align_of(ptr_type),
         cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
@@ -174,7 +174,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
     let data_layout = &cx.tcx.data_layout;
     let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
 
-    match fat_pointer_kind(cx, pointee_type) {
+    match wide_pointer_kind(cx, pointee_type) {
         None => {
             // This is a thin pointer. Create a regular pointer type and give it the correct name.
             assert_eq!(
@@ -197,7 +197,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
 
             DINodeCreationResult { di_node, already_stored_in_typemap: false }
         }
-        Some(fat_pointer_kind) => {
+        Some(wide_pointer_kind) => {
             type_map::build_type_with_children(
                 cx,
                 type_map::stub(
@@ -210,7 +210,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     DIFlags::FlagZero,
                 ),
                 |cx, owner| {
-                    // FIXME: If this fat pointer is a `Box` then we don't want to use its
+                    // FIXME: If this wide pointer is a `Box` then we don't want to use its
                     //        type layout and instead use the layout of the raw pointer inside
                     //        of it.
                     //        The proper way to handle this is to not treat Box as a pointer
@@ -227,16 +227,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     };
 
                     let layout = cx.layout_of(layout_type);
-                    let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
-                    let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
+                    let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR);
+                    let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA);
 
-                    let (addr_field_name, extra_field_name) = match fat_pointer_kind {
-                        FatPtrKind::Dyn => ("pointer", "vtable"),
-                        FatPtrKind::Slice => ("data_ptr", "length"),
+                    let (addr_field_name, extra_field_name) = match wide_pointer_kind {
+                        WidePtrKind::Dyn => ("pointer", "vtable"),
+                        WidePtrKind::Slice => ("data_ptr", "length"),
                     };
 
-                    assert_eq!(abi::FAT_PTR_ADDR, 0);
-                    assert_eq!(abi::FAT_PTR_EXTRA, 1);
+                    assert_eq!(abi::WIDE_PTR_ADDR, 0);
+                    assert_eq!(abi::WIDE_PTR_EXTRA, 1);
 
                     // The data pointer type is a regular, thin pointer, regardless of whether this
                     // is a slice or a trait object.
@@ -258,7 +258,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             owner,
                             addr_field_name,
                             (addr_field.size, addr_field.align.abi),
-                            layout.fields.offset(abi::FAT_PTR_ADDR),
+                            layout.fields.offset(abi::WIDE_PTR_ADDR),
                             DIFlags::FlagZero,
                             data_ptr_type_di_node,
                         ),
@@ -267,7 +267,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             owner,
                             extra_field_name,
                             (extra_field.size, extra_field.align.abi),
-                            layout.fields.offset(abi::FAT_PTR_EXTRA),
+                            layout.fields.offset(abi::WIDE_PTR_EXTRA),
                             DIFlags::FlagZero,
                             type_di_node(cx, extra_field.ty),
                         ),
@@ -391,7 +391,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
 ///
 /// NOTE: We currently emit just emit the debuginfo for the element type here
 /// (i.e. `T` for slices and `u8` for `str`), so that we end up with
-/// `*const T` for the `data_ptr` field of the corresponding fat-pointer
+/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
 /// debuginfo of `&[T]`.
 ///
 /// It would be preferable and more accurate if we emitted a DIArray of T
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index acb15449ce3..960487ada16 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -49,23 +49,23 @@ pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId
 }
 
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) enum FatPtrKind {
+pub(crate) enum WidePtrKind {
     Slice,
     Dyn,
 }
 
 /// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
-/// if the second field of the fat pointer is a length or a vtable-pointer.
-/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
+/// if the second field of the wide pointer is a length or a vtable-pointer.
+/// If `pointee_ty` does not require a wide pointer (because it is Sized) then
 /// the function returns `None`.
-pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
+pub(crate) fn wide_pointer_kind<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     pointee_ty: Ty<'tcx>,
-) -> Option<FatPtrKind> {
+) -> Option<WidePtrKind> {
     let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
     let layout = cx.layout_of(pointee_tail_ty);
     trace!(
-        "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
+        "wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
         pointee_tail_ty,
         layout,
         layout.is_unsized()
@@ -76,8 +76,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
     }
 
     match *pointee_tail_ty.kind() {
-        ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
-        ty::Dynamic(..) => Some(FatPtrKind::Dyn),
+        ty::Str | ty::Slice(_) => Some(WidePtrKind::Slice),
+        ty::Dynamic(..) => Some(WidePtrKind::Dyn),
         ty::Foreign(_) => {
             // Assert that pointers to foreign types really are thin:
             assert_eq!(
@@ -90,7 +90,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
             // For all other pointee types we should already have returned None
             // at the beginning of the function.
             panic!(
-                "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
+                "wide_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
             )
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c66c80da9fc..30c6f08e894 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -2185,7 +2185,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: in_elem
@@ -2200,7 +2200,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
-                require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
+                require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
                     span,
                     name,
                     ty: out_elem
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 6e429a1674a..7071dd86ee0 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -199,7 +199,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
         // layout.
         if let Abi::Scalar(scalar) = self.abi {
             // Use a different cache for scalars because pointers to DSTs
-            // can be either fat or thin (data pointers of fat pointers).
+            // can be either wide or thin (data pointers of wide pointers).
             if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
                 return llty;
             }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 9091602d75b..f02b0f72674 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -82,7 +82,7 @@ codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphizati
 
 codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
 
-codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
+codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}`
 
 codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
 
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 08b326e3ac3..ab909abcead 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -916,8 +916,8 @@ pub enum InvalidMonomorphization<'tcx> {
         ret_ty: Ty<'tcx>,
     },
 
-    #[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)]
-    CastFatPointer {
+    #[diag(codegen_ssa_invalid_monomorphization_cast_wide_pointer, code = E0511)]
+    CastWidePointer {
         #[primary_span]
         span: Span,
         name: Symbol,
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 162d14272a5..3129b9ac203 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -156,7 +156,7 @@ pub struct NativeLib {
     pub kind: NativeLibKind,
     pub name: Symbol,
     pub filename: Option<Symbol>,
-    pub cfg: Option<ast::MetaItem>,
+    pub cfg: Option<ast::NestedMetaItem>,
     pub verbatim: bool,
     pub dll_imports: Vec<cstore::DllImport>,
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index c4fb24aa625..8bd172a9ce6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -133,9 +133,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 enum LocalRef<'tcx, V> {
     Place(PlaceRef<'tcx, V>),
     /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
-    /// `*p` is the fat pointer that references the actual unsized place.
+    /// `*p` is the wide pointer that references the actual unsized place.
     /// Every time it is initialized, we have to reallocate the place
-    /// and update the fat pointer. That's the reason why it is indirect.
+    /// and update the wide pointer. That's the reason why it is indirect.
     UnsizedPlace(PlaceRef<'tcx, V>),
     /// The backend [`OperandValue`] has already been generated.
     Operand(OperandRef<'tcx, V>),
@@ -429,7 +429,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 // Unsized indirect qrguments
                 PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
                     // As the storage for the indirect argument lives during
-                    // the whole function call, we just copy the fat pointer.
+                    // the whole function call, we just copy the wide pointer.
                     let llarg = bx.get_param(llarg_idx);
                     llarg_idx += 1;
                     let llextra = bx.get_param(llarg_idx);
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 17f66c12a03..0bcd7d6d081 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -41,7 +41,7 @@ pub enum OperandValue<V> {
     /// The backend value in this variant must be the *immediate* backend type,
     /// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`].
     Immediate(V),
-    /// A pair of immediate LLVM values. Used by fat pointers too.
+    /// A pair of immediate LLVM values. Used by wide pointers too.
     ///
     /// An `OperandValue` *must* be this variant for any type for which
     /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`.
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index f9c0f3ce941..a132ca69540 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -38,10 +38,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 ref source,
                 _,
             ) => {
-                // The destination necessarily contains a fat pointer, so if
-                // it's a scalar pair, it's a fat pointer or newtype thereof.
+                // The destination necessarily contains a wide pointer, so if
+                // it's a scalar pair, it's a wide pointer or newtype thereof.
                 if bx.cx().is_backend_scalar_pair(dest.layout) {
-                    // Into-coerce of a thin pointer to a fat pointer -- just
+                    // Into-coerce of a thin pointer to a wide pointer -- just
                     // use the operand path.
                     let temp = self.codegen_rvalue_operand(bx, rvalue);
                     temp.val.store(bx, dest);
@@ -519,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             if bx.cx().is_backend_scalar_pair(cast) {
                                 OperandValue::Pair(data_ptr, meta)
                             } else {
-                                // Cast of fat-ptr to thin-ptr is an extraction of data-ptr.
+                                // Cast of wide-ptr to thin-ptr is an extraction of data-ptr.
                                 OperandValue::Immediate(data_ptr)
                             }
                         } else {
@@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     (
                         OperandValue::Pair(lhs_addr, lhs_extra),
                         OperandValue::Pair(rhs_addr, rhs_extra),
-                    ) => self.codegen_fat_ptr_binop(
+                    ) => self.codegen_wide_ptr_binop(
                         bx,
                         op,
                         lhs_addr,
@@ -984,7 +984,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
     }
 
-    fn codegen_fat_ptr_binop(
+    fn codegen_wide_ptr_binop(
         &mut self,
         bx: &mut Bx,
         op: mir::BinOp,
@@ -1021,7 +1021,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.or(lhs, rhs)
             }
             _ => {
-                bug!("unexpected fat ptr binop");
+                bug!("unexpected wide ptr binop");
             }
         }
     }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 565a7d16242..30b5a8d70bc 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -204,12 +204,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert!(src.layout.ty.is_any_ptr());
         assert!(cast_to.ty.is_unsafe_ptr());
-        // Handle casting any ptr to raw ptr (might be a fat ptr).
+        // Handle casting any ptr to raw ptr (might be a wide ptr).
         if cast_to.size == src.layout.size {
-            // Thin or fat pointer that just has the ptr kind of target type changed.
+            // Thin or wide pointer that just has the ptr kind of target type changed.
             return interp_ok(ImmTy::from_immediate(**src, cast_to));
         } else {
-            // Casting the metadata away from a fat ptr.
+            // Casting the metadata away from a wide ptr.
             assert_eq!(src.layout.size, 2 * self.pointer_size());
             assert_eq!(cast_to.size, self.pointer_size());
             assert!(src.layout.ty.is_unsafe_ptr());
diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs
index 7ff1339c5ab..3d6d0003483 100644
--- a/compiler/rustc_data_structures/src/stack.rs
+++ b/compiler/rustc_data_structures/src/stack.rs
@@ -5,7 +5,11 @@ const RED_ZONE: usize = 100 * 1024; // 100k
 
 // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
 // on. This flag has performance relevant characteristics. Don't set it too high.
+#[cfg(not(target_os = "aix"))]
 const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB
+// LLVM for AIX doesn't feature TCO, increase recursion size for workaround.
+#[cfg(target_os = "aix")]
+const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB
 
 /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
 /// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit
diff --git a/compiler/rustc_error_codes/src/error_codes/E0607.md b/compiler/rustc_error_codes/src/error_codes/E0607.md
index 0545246929f..8ebc227114d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0607.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0607.md
@@ -1,4 +1,4 @@
-A cast between a thin and a fat pointer was attempted.
+A cast between a thin and a wide pointer was attempted.
 
 Erroneous code example:
 
@@ -7,18 +7,18 @@ let v = core::ptr::null::<u8>();
 v as *const [u8];
 ```
 
-First: what are thin and fat pointers?
+First: what are thin and wide pointers?
 
 Thin pointers are "simple" pointers: they are purely a reference to a memory
 address.
 
-Fat pointers are pointers referencing Dynamically Sized Types (also called
+Wide pointers are pointers referencing Dynamically Sized Types (also called
 DSTs). DSTs don't have a statically known size, therefore they can only exist
 behind some kind of pointer that contains additional information. For example,
 slices and trait objects are DSTs. In the case of slices, the additional
-information the fat pointer holds is their size.
+information the wide pointer holds is their size.
 
-To fix this error, don't try to cast directly between thin and fat pointers.
+To fix this error, don't try to cast directly between thin and wide pointers.
 
 For more information about type casts, take a look at the section of the
 [The Rust Reference][1] on type cast expressions.
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 32088374277..af56169fd60 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{
     AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
 };
-use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
+use rustc_ast::{
+    self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
+};
 use rustc_attr as attr;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::{
@@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
-pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
+pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
     let span = meta_item.span;
     match meta_item.meta_item_list() {
         None => {
@@ -464,7 +466,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
             sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
             None
         }
-        Some([single]) => match single.meta_item() {
+        Some([single]) => match single.meta_item_or_bool() {
             Some(meta_item) => Some(meta_item),
             None => {
                 sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index c5530097e96..380e36fe405 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -371,6 +371,8 @@ declare_features! (
     (unstable, async_for_loop, "1.77.0", Some(118898)),
     /// Allows using C-variadics.
     (unstable, c_variadic, "1.34.0", Some(44930)),
+    /// Allows the use of `#[cfg(<true/false>)]`.
+    (unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
     /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
     (unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
     /// Provides the relocation model information as cfg entry
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 71216023ecc..2ef6fa53f4e 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2632,7 +2632,7 @@ impl<'hir> Ty<'hir> {
             }
             TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
             TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
-            TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
+            TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
             TyKind::Path(QPath::TypeRelative(ty, segment)) => {
                 ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args)
             }
@@ -2749,6 +2749,8 @@ pub struct BareFnTy<'hir> {
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct OpaqueTy<'hir> {
+    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
@@ -2762,10 +2764,7 @@ pub struct OpaqueTy<'hir> {
     /// This mapping associated a captured lifetime (first parameter) with the new
     /// early-bound lifetime that was generated for the opaque.
     pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)],
-    /// Whether the opaque is a return-position impl trait (or async future)
-    /// originating from a trait method. This makes it so that the opaque is
-    /// lowered as an associated type.
-    pub in_trait: bool,
+    pub span: Span,
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -2802,13 +2801,29 @@ pub struct PreciseCapturingNonLifetimeArg {
     pub res: Res,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
+pub enum RpitContext {
+    Trait,
+    TraitImpl,
+}
+
 /// From whence the opaque type came.
 #[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
 pub enum OpaqueTyOrigin {
     /// `-> impl Trait`
-    FnReturn(LocalDefId),
+    FnReturn {
+        /// The defining function.
+        parent: LocalDefId,
+        // Whether this is an RPITIT (return position impl trait in trait)
+        in_trait_or_impl: Option<RpitContext>,
+    },
     /// `async fn`
-    AsyncFn(LocalDefId),
+    AsyncFn {
+        /// The defining function.
+        parent: LocalDefId,
+        // Whether this is an AFIT (async fn in trait)
+        in_trait_or_impl: Option<RpitContext>,
+    },
     /// type aliases: `type Foo = impl Trait;`
     TyAlias {
         /// The type alias or associated type parent of the TAIT/ATPIT
@@ -2856,7 +2871,7 @@ pub enum TyKind<'hir> {
     /// possibly parameters) that are actually bound on the `impl Trait`.
     ///
     /// The last parameter specifies whether this opaque appears in a trait definition.
-    OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
+    OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TraitObject(
@@ -3325,8 +3340,6 @@ impl<'hir> Item<'hir> {
         expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
             ItemKind::TyAlias(ty, generics), (ty, generics);
 
-        expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty;
-
         expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics);
 
         expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>),
@@ -3439,8 +3452,6 @@ pub enum ItemKind<'hir> {
     GlobalAsm(&'hir InlineAsm<'hir>),
     /// A type alias, e.g., `type Foo = Bar<u8>`.
     TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
-    /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
-    OpaqueTy(&'hir OpaqueTy<'hir>),
     /// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
     Enum(EnumDef<'hir>, &'hir Generics<'hir>),
     /// A struct definition, e.g., `struct Foo<A> {x: A}`.
@@ -3484,7 +3495,6 @@ impl ItemKind<'_> {
             ItemKind::Fn(_, ref generics, _)
             | ItemKind::TyAlias(_, ref generics)
             | ItemKind::Const(_, ref generics, _)
-            | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
             | ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics)
@@ -3507,7 +3517,6 @@ impl ItemKind<'_> {
             ItemKind::ForeignMod { .. } => "extern block",
             ItemKind::GlobalAsm(..) => "global asm item",
             ItemKind::TyAlias(..) => "type alias",
-            ItemKind::OpaqueTy(..) => "opaque type",
             ItemKind::Enum(..) => "enum",
             ItemKind::Struct(..) => "struct",
             ItemKind::Union(..) => "union",
@@ -3794,6 +3803,7 @@ pub enum Node<'hir> {
     Ty(&'hir Ty<'hir>),
     AssocItemConstraint(&'hir AssocItemConstraint<'hir>),
     TraitRef(&'hir TraitRef<'hir>),
+    OpaqueTy(&'hir OpaqueTy<'hir>),
     Pat(&'hir Pat<'hir>),
     PatField(&'hir PatField<'hir>),
     Arm(&'hir Arm<'hir>),
@@ -3859,6 +3869,7 @@ impl<'hir> Node<'hir> {
             | Node::Crate(..)
             | Node::Ty(..)
             | Node::TraitRef(..)
+            | Node::OpaqueTy(..)
             | Node::Infer(..)
             | Node::WhereBoundPredicate(..)
             | Node::ArrayLenInfer(..)
@@ -3984,6 +3995,7 @@ impl<'hir> Node<'hir> {
             | Node::TraitItem(TraitItem { generics, .. })
             | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
             Node::Item(item) => item.kind.generics(),
+            Node::OpaqueTy(opaque) => Some(opaque.generics),
             _ => None,
         }
     }
@@ -4043,6 +4055,7 @@ impl<'hir> Node<'hir> {
         expect_ty,            &'hir Ty<'hir>,           Node::Ty(n),           n;
         expect_assoc_item_constraint,  &'hir AssocItemConstraint<'hir>,  Node::AssocItemConstraint(n),  n;
         expect_trait_ref,     &'hir TraitRef<'hir>,     Node::TraitRef(n),     n;
+        expect_opaque_ty,     &'hir OpaqueTy<'hir>,     Node::OpaqueTy(n),     n;
         expect_pat,           &'hir Pat<'hir>,          Node::Pat(n),          n;
         expect_pat_field,     &'hir PatField<'hir>,     Node::PatField(n),     n;
         expect_arm,           &'hir Arm<'hir>,          Node::Arm(n),          n;
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 4da32245785..58916d05865 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -111,6 +111,7 @@ impl<'a> FnKind<'a> {
 pub trait Map<'hir> {
     /// Retrieves the `Node` corresponding to `id`.
     fn hir_node(&self, hir_id: HirId) -> Node<'hir>;
+    fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir>;
     fn body(&self, id: BodyId) -> &'hir Body<'hir>;
     fn item(&self, id: ItemId) -> &'hir Item<'hir>;
     fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
@@ -123,6 +124,9 @@ impl<'hir> Map<'hir> for ! {
     fn hir_node(&self, _: HirId) -> Node<'hir> {
         *self;
     }
+    fn hir_node_by_def_id(&self, _: LocalDefId) -> Node<'hir> {
+        *self;
+    }
     fn body(&self, _: BodyId) -> &'hir Body<'hir> {
         *self;
     }
@@ -423,6 +427,9 @@ pub trait Visitor<'v>: Sized {
     fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> Self::Result {
         walk_poly_trait_ref(self, t)
     }
+    fn visit_opaque_ty(&mut self, opaque: &'v OpaqueTy<'v>) -> Self::Result {
+        walk_opaque_ty(self, opaque)
+    }
     fn visit_variant_data(&mut self, s: &'v VariantData<'v>) -> Self::Result {
         walk_struct_def(self, s)
     }
@@ -536,11 +543,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_ty(ty));
             try_visit!(visitor.visit_generics(generics));
         }
-        ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
-            try_visit!(visitor.visit_id(item.hir_id()));
-            try_visit!(walk_generics(visitor, generics));
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             try_visit!(visitor.visit_generics(generics));
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
@@ -894,8 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
         TyKind::Path(ref qpath) => {
             try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
         }
-        TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
-            try_visit!(visitor.visit_nested_item(item_id));
+        TyKind::OpaqueDef(opaque, lifetimes) => {
+            try_visit!(visitor.visit_opaque_ty(opaque));
             walk_list!(visitor, visit_generic_arg, lifetimes);
         }
         TyKind::Array(ref ty, ref length) => {
@@ -1185,6 +1187,15 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
     visitor.visit_trait_ref(&trait_ref.trait_ref)
 }
 
+pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result {
+    let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } =
+        opaque;
+    try_visit!(visitor.visit_id(hir_id));
+    try_visit!(walk_generics(visitor, generics));
+    walk_list!(visitor, visit_param_bound, bounds);
+    V::Result::output()
+}
+
 pub fn walk_struct_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     struct_definition: &'v VariantData<'v>,
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 155270ca6a7..6ff57396b4a 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -34,7 +34,6 @@ pub enum Target {
     ForeignMod,
     GlobalAsm,
     TyAlias,
-    OpaqueTy,
     Enum,
     Variant,
     Struct,
@@ -79,7 +78,6 @@ impl Target {
             | Target::ForeignMod
             | Target::GlobalAsm
             | Target::TyAlias
-            | Target::OpaqueTy
             | Target::Enum
             | Target::Variant
             | Target::Struct
@@ -114,7 +112,6 @@ impl Target {
             ItemKind::ForeignMod { .. } => Target::ForeignMod,
             ItemKind::GlobalAsm(..) => Target::GlobalAsm,
             ItemKind::TyAlias(..) => Target::TyAlias,
-            ItemKind::OpaqueTy(..) => Target::OpaqueTy,
             ItemKind::Enum(..) => Target::Enum,
             ItemKind::Struct(..) => Target::Struct,
             ItemKind::Union(..) => Target::Union,
@@ -137,7 +134,6 @@ impl Target {
             DefKind::ForeignMod => Target::ForeignMod,
             DefKind::GlobalAsm => Target::GlobalAsm,
             DefKind::TyAlias => Target::TyAlias,
-            DefKind::OpaqueTy => Target::OpaqueTy,
             DefKind::Enum => Target::Enum,
             DefKind::Struct => Target::Struct,
             DefKind::Union => Target::Union,
@@ -191,7 +187,6 @@ impl Target {
             Target::ForeignMod => "foreign module",
             Target::GlobalAsm => "global asm",
             Target::TyAlias => "type alias",
-            Target::OpaqueTy => "opaque type",
             Target::Enum => "enum",
             Target::Variant => "enum variant",
             Target::Struct => "struct",
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d725772a5b3..eb62ff86c71 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -252,10 +252,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 item = tcx.hir().expect_item(def_id);
-    let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
-        tcx.dcx().span_bug(item.span, "expected opaque item");
-    };
+    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).
@@ -265,16 +262,16 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         return;
     }
 
-    let span = tcx.def_span(item.owner_id.def_id);
+    let span = tcx.def_span(def_id);
 
-    if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
+    if tcx.type_of(def_id).instantiate_identity().references_error() {
         return;
     }
-    if check_opaque_for_cycles(tcx, item.owner_id.def_id, span).is_err() {
+    if check_opaque_for_cycles(tcx, def_id, span).is_err() {
         return;
     }
 
-    let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, origin);
+    let _ = check_opaque_meets_bounds(tcx, def_id, span, origin);
 }
 
 /// Checks that an opaque type does not contain cycles.
@@ -336,9 +333,9 @@ fn check_opaque_meets_bounds<'tcx>(
     origin: &hir::OpaqueTyOrigin,
 ) -> Result<(), ErrorGuaranteed> {
     let defining_use_anchor = match *origin {
-        hir::OpaqueTyOrigin::FnReturn(did)
-        | hir::OpaqueTyOrigin::AsyncFn(did)
-        | hir::OpaqueTyOrigin::TyAlias { parent: did, .. } => did,
+        hir::OpaqueTyOrigin::FnReturn { parent, .. }
+        | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
+        | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
@@ -346,8 +343,8 @@ fn check_opaque_meets_bounds<'tcx>(
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let args = match *origin {
-        hir::OpaqueTyOrigin::FnReturn(parent)
-        | hir::OpaqueTyOrigin::AsyncFn(parent)
+        hir::OpaqueTyOrigin::FnReturn { parent, .. }
+        | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
         | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
             tcx, parent,
         )
@@ -409,7 +406,7 @@ fn check_opaque_meets_bounds<'tcx>(
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
 
-    if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
+    if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } = origin {
         // HACK: this should also fall through to the hidden type check below, but the original
         // implementation had a bug where equivalent lifetimes are not identical. This caused us
         // to reject existing stable code that is otherwise completely fine. The real fix is to
@@ -481,8 +478,7 @@ fn sanity_check_found_hidden_type<'tcx>(
 /// 2. Checking that all lifetimes that are implicitly captured are mentioned.
 /// 3. Asserting that all parameters mentioned in the captures list are invariant.
 fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
-    let hir::OpaqueTy { bounds, .. } =
-        *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+    let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
     let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
         hir::GenericBound::Use(bounds, ..) => Some(bounds),
         _ => None,
@@ -736,8 +732,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             check_opaque_precise_captures(tcx, def_id);
 
             let origin = tcx.opaque_type_origin(def_id);
-            if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
-            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
+            if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
+            | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_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()
             {
@@ -1105,7 +1101,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
         // Check that we use types valid for use in the lanes of a SIMD "vector register"
         // These are scalar types which directly match a "machine" type
         // Yes: Integers, floats, "thin" pointers
-        // No: char, "fat" pointers, compound types
+        // No: char, "wide" pointers, compound types
         match element_ty.kind() {
             ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors
             ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index e07b587508a..80334c6efe7 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -93,9 +93,9 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         // it's a refinement to a TAIT.
         if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| {
             matches!(
-                node.expect_item().expect_opaque_ty().origin,
-                hir::OpaqueTyOrigin::AsyncFn(def_id)  | hir::OpaqueTyOrigin::FnReturn(def_id)
-                    if def_id == impl_m.def_id.expect_local()
+                node.expect_opaque_ty().origin,
+                hir::OpaqueTyOrigin::AsyncFn { parent, .. }  | hir::OpaqueTyOrigin::FnReturn { parent, .. }
+                    if parent == impl_m.def_id.expect_local()
             )
         }) {
             report_mismatched_rpitit_signature(
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 02d23b95d46..3a9d2640eee 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -185,15 +185,16 @@ where
     }
 }
 
-fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
-    let node = tcx.hir_owner_node(def_id);
+fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+    let node = tcx.hir_node_by_def_id(def_id);
     let mut res = match node {
-        hir::OwnerNode::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
-        hir::OwnerNode::Item(item) => check_item(tcx, item),
-        hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item),
-        hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item),
-        hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item),
-        hir::OwnerNode::Synthetic => unreachable!(),
+        hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),
+        hir::Node::Item(item) => check_item(tcx, item),
+        hir::Node::TraitItem(item) => check_trait_item(tcx, item),
+        hir::Node::ImplItem(item) => check_impl_item(tcx, item),
+        hir::Node::ForeignItem(item) => check_foreign_item(tcx, item),
+        hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)),
+        _ => unreachable!(),
     };
 
     if let Some(generics) = node.generics() {
@@ -201,6 +202,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorG
             res = res.and(check_param_wf(tcx, param));
         }
     }
+
     res
 }
 
@@ -2172,10 +2174,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
 
 fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
     let items = tcx.hir_module_items(module);
-    let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
-    res = res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
-    res = res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
-    res = res.and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)));
+    let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id));
+    res =
+        res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
+    res =
+        res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
+    res = res
+        .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)));
+    res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item)));
     if module == LocalModDefId::CRATE_DEF_ID {
         super::entry::check_for_entry_fn(tcx);
     }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index bea8d28a9f7..76c75d976ee 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -424,7 +424,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
             // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
             // when this coercion occurs, we would be changing the
             // field `ptr` from a thin pointer of type `*mut [i32;
-            // 3]` to a fat pointer of type `*mut [i32]` (with
+            // 3]` to a wide pointer of type `*mut [i32]` (with
             // extra data `3`). **The purpose of this check is to
             // make sure that we know how to do this conversion.**
             //
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 93b021be245..640907c3e4a 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -260,8 +260,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
         | hir::ItemKind::Trait(_, _, generics, ..)
         | hir::ItemKind::Impl(hir::Impl { generics, .. })
         | hir::ItemKind::Struct(_, generics) => (generics, true),
-        hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
-        | hir::ItemKind::TyAlias(_, generics) => (generics, false),
+        hir::ItemKind::TyAlias(_, generics) => (generics, false),
         // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
         _ => return,
     };
@@ -328,6 +327,19 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
+    /// Don't call `type_of` on opaque types, since that depends on type checking function bodies.
+    /// `check_item_type` ensures that it's called instead.
+    fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
+        let def_id = opaque.def_id;
+        self.tcx.ensure().generics_of(def_id);
+        self.tcx.ensure().predicates_of(def_id);
+        self.tcx.ensure().explicit_item_bounds(def_id);
+        self.tcx.ensure().explicit_item_super_predicates(def_id);
+        self.tcx.ensure().item_bounds(def_id);
+        self.tcx.ensure().item_super_predicates(def_id);
+        intravisit::walk_opaque_ty(self, opaque);
+    }
+
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         lower_trait_item(self.tcx, trait_item.trait_item_id());
         intravisit::walk_trait_item(self, trait_item);
@@ -731,18 +743,6 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
         }
 
-        // Don't call `type_of` on opaque types, since that depends on type
-        // checking function bodies. `check_item_type` ensures that it's called
-        // instead.
-        hir::ItemKind::OpaqueTy(..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().predicates_of(def_id);
-            tcx.ensure().explicit_item_bounds(def_id);
-            tcx.ensure().explicit_item_super_predicates(def_id);
-            tcx.ensure().item_bounds(def_id);
-            tcx.ensure().item_super_predicates(def_id);
-        }
-
         hir::ItemKind::TyAlias(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
@@ -1852,12 +1852,8 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
 }
 
 fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
-    match tcx.hir_node_by_def_id(def_id) {
-        Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
-            matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
-        }
-        _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
-    }
+    let opaque = tcx.hir().expect_opaque_ty(def_id);
+    matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
 }
 
 fn rendered_precise_capturing_args<'tcx>(
@@ -1870,12 +1866,10 @@ fn rendered_precise_capturing_args<'tcx>(
         return tcx.rendered_precise_capturing_args(opaque_def_id);
     }
 
-    tcx.hir_node_by_def_id(def_id).expect_item().expect_opaque_ty().bounds.iter().find_map(
-        |bound| match bound {
-            hir::GenericBound::Use(args, ..) => {
-                Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
-            }
-            _ => None,
-        },
-    )
+    tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound {
+        hir::GenericBound::Use(args, ..) => {
+            Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name())))
+        }
+        _ => None,
+    })
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index d76d9213129..8648a7d1e32 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -1,4 +1,3 @@
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::intravisit;
 use rustc_middle::hir::nested_filter::OnlyBodies;
@@ -10,12 +9,10 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
         return;
     }
 
-    for id in tcx.hir().items() {
-        let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
-
-        let ty = tcx.type_of(id.owner_id).instantiate_identity();
-
-        tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty });
+    for id in tcx.hir_crate_items(()).opaques() {
+        let ty = tcx.type_of(id).instantiate_identity();
+        let span = tcx.def_span(id);
+        tcx.dcx().emit_err(crate::errors::TypeOf { span, ty });
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 0a8eef2006d..14b6b17ed18 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -24,6 +24,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) =
         tcx.opt_rpitit_info(def_id.to_def_id())
     {
+        debug!("RPITIT fn_def_id={fn_def_id:?} opaque_def_id={opaque_def_id:?}");
         let trait_def_id = tcx.parent(fn_def_id);
         let opaque_ty_generics = tcx.generics_of(opaque_def_id);
         let opaque_ty_parent_count = opaque_ty_generics.parent_count;
@@ -207,36 +208,33 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
             Some(tcx.typeck_root_def_id(def_id.to_def_id()))
         }
-        Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(&hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                in_trait,
-                ..
-            }) => {
-                if in_trait {
-                    assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
-                } else {
-                    assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
-                }
-                Some(fn_def_id.to_def_id())
+        Node::OpaqueTy(&hir::OpaqueTy {
+            origin:
+                hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, in_trait_or_impl }
+                | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
+            ..
+        }) => {
+            if in_trait_or_impl.is_some() {
+                assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn);
+            } else {
+                assert_matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn);
             }
-            ItemKind::OpaqueTy(&hir::OpaqueTy {
-                origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
-                ..
-            }) => {
-                if in_assoc_ty {
-                    assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
-                } else {
-                    assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
-                }
-                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
-                // Opaque types are always nested within another item, and
-                // inherit the generics of the item.
-                Some(parent.to_def_id())
+            Some(fn_def_id.to_def_id())
+        }
+        Node::OpaqueTy(&hir::OpaqueTy {
+            origin: hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty },
+            ..
+        }) => {
+            if in_assoc_ty {
+                assert_matches!(tcx.def_kind(parent), DefKind::AssocTy);
+            } else {
+                assert_matches!(tcx.def_kind(parent), DefKind::TyAlias);
             }
-            _ => None,
-        },
+            debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent);
+            // Opaque types are always nested within another item, and
+            // inherit the generics of the item.
+            Some(parent.to_def_id())
+        }
         _ => None,
     };
 
@@ -272,13 +270,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 ItemKind::TyAlias(..)
                 | ItemKind::Enum(..)
                 | ItemKind::Struct(..)
-                | ItemKind::OpaqueTy(..)
                 | ItemKind::Union(..) => (None, Defaults::Allowed),
                 ItemKind::Const(..) => (None, Defaults::Deny),
                 _ => (None, Defaults::FutureCompatDisallowed),
             }
         }
 
+        Node::OpaqueTy(..) => (None, Defaults::Allowed),
+
         // GATs
         Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
             (None, Defaults::Deny)
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index f44b4728ad5..4346504450d 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -335,8 +335,7 @@ pub(super) fn explicit_item_bounds_with_filter(
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
         Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
-            let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item();
-            let opaque_ty = item.expect_opaque_ty();
+            let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty();
             let item_ty = Ty::new_projection_from_args(
                 tcx,
                 def_id.to_def_id(),
@@ -347,7 +346,7 @@ pub(super) fn explicit_item_bounds_with_filter(
                 opaque_def_id.expect_local(),
                 opaque_ty.bounds,
                 item_ty,
-                item.span,
+                opaque_ty.span,
                 filter,
             );
             assert_only_contains_predicates_from(filter, bounds, item_ty);
@@ -369,42 +368,46 @@ pub(super) fn explicit_item_bounds_with_filter(
             span,
             ..
         }) => associated_type_bounds(tcx, def_id, bounds, *span, filter),
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
-            span,
-            ..
-        }) => {
-            let args = GenericArgs::identity_for_item(tcx, def_id);
-            let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
-            let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter);
-            assert_only_contains_predicates_from(filter, bounds, item_ty);
-            bounds
-        }
-        // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`, when we're
-        // asking for the item bounds of the *opaques* in a trait's default method signature, we
-        // need to map these projections back to opaques.
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }),
-            span,
-            ..
-        }) => {
-            let (hir::OpaqueTyOrigin::FnReturn(fn_def_id)
-            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = *origin
-            else {
-                span_bug!(*span, "RPITIT cannot be a TAIT, but got origin {origin:?}");
-            };
-            let args = GenericArgs::identity_for_item(tcx, def_id);
-            let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
-            let bounds = &*tcx.arena.alloc_slice(
-                &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter)
-                    .to_vec()
-                    .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }),
-            );
-            assert_only_contains_predicates_from(filter, bounds, item_ty);
-            bounds
-        }
+        hir::Node::OpaqueTy(hir::OpaqueTy { bounds, origin, span, .. }) => match origin {
+            // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`,
+            // when we're asking for the item bounds of the *opaques* in a trait's default
+            // method signature, we need to map these projections back to opaques.
+            rustc_hir::OpaqueTyOrigin::FnReturn {
+                parent,
+                in_trait_or_impl: Some(hir::RpitContext::Trait),
+            }
+            | rustc_hir::OpaqueTyOrigin::AsyncFn {
+                parent,
+                in_trait_or_impl: Some(hir::RpitContext::Trait),
+            } => {
+                let args = GenericArgs::identity_for_item(tcx, def_id);
+                let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
+                let bounds = &*tcx.arena.alloc_slice(
+                    &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter)
+                        .to_vec()
+                        .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: parent.to_def_id() }),
+                );
+                assert_only_contains_predicates_from(filter, bounds, item_ty);
+                bounds
+            }
+            rustc_hir::OpaqueTyOrigin::FnReturn {
+                parent: _,
+                in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+            }
+            | rustc_hir::OpaqueTyOrigin::AsyncFn {
+                parent: _,
+                in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+            }
+            | rustc_hir::OpaqueTyOrigin::TyAlias { parent: _, .. } => {
+                let args = GenericArgs::identity_for_item(tcx, def_id);
+                let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
+                let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter);
+                assert_only_contains_predicates_from(filter, bounds, item_ty);
+                bounds
+            }
+        },
         hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
-        _ => bug!("item_bounds called on {:?}", def_id),
+        node => bug!("item_bounds called on {def_id:?} => {node:?}"),
     };
 
     ty::EarlyBinder::bind(bounds)
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 9e970462205..6d30f7c7b9d 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -330,9 +330,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // Opaque types duplicate some of their generic parameters.
     // We create bi-directional Outlives predicates between the original
     // and the duplicated parameter, to ensure that they do not get out of sync.
-    if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
+    if let Node::OpaqueTy(..) = node {
         let opaque_ty_node = tcx.parent_hir_node(hir_id);
-        let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node
+        let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node
         else {
             bug!("unexpected {opaque_ty_node:?}")
         };
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index c9b949ad88d..c8852a3a369 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -11,10 +11,13 @@ use std::fmt;
 
 use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
+use rustc_hir::{
+    GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, LifetimeName, Node,
+};
 use rustc_macros::extension;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::*;
@@ -74,7 +77,7 @@ impl ResolvedArg {
 struct NamedVarMap {
     // maps from every use of a named (not anonymous) bound var to a
     // `ResolvedArg` describing how that variable is bound
-    defs: HirIdMap<ResolvedArg>,
+    defs: ItemLocalMap<ResolvedArg>,
 
     // Maps relevant hir items to the bound vars on them. These include:
     // - function defs
@@ -82,7 +85,7 @@ struct NamedVarMap {
     // - closures
     // - trait refs
     // - bound types (like `T` in `for<'a> T<'a>: Foo`)
-    late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
+    late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
 }
 
 struct BoundVarContext<'a, 'tcx> {
@@ -225,10 +228,10 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         resolve_bound_vars,
 
-        named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id),
+        named_variable_map: |tcx, id| &tcx.resolve_bound_vars(id).defs,
         is_late_bound_map,
         object_lifetime_default,
-        late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id),
+        late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars,
 
         ..*providers
     };
@@ -265,16 +268,12 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
         hir::OwnerNode::Synthetic => unreachable!(),
     }
 
-    let mut rl = ResolveBoundVars::default();
-
-    for (hir_id, v) in named_variable_map.defs {
-        let map = rl.defs.entry(hir_id.owner).or_default();
-        map.insert(hir_id.local_id, v);
-    }
-    for (hir_id, v) in named_variable_map.late_bound_vars {
-        let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
-        map.insert(hir_id.local_id, v);
-    }
+    let defs = named_variable_map.defs.into_sorted_stable_ord();
+    let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
+    let rl = ResolveBoundVars {
+        defs: SortedMap::from_presorted_elements(defs),
+        late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
+    };
 
     debug!(?rl.defs);
     debug!(?rl.late_bound_vars);
@@ -340,7 +339,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Binder { hir_id, .. } => {
                     // Nested poly trait refs have the binders concatenated
                     let mut full_binders =
-                        self.map.late_bound_vars.entry(*hir_id).or_default().clone();
+                        self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone();
                     full_binders.extend(supertrait_bound_vars);
                     break (full_binders, BinderScopeType::Concatenating);
                 }
@@ -487,6 +486,31 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
+    fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
+        // We want to start our early-bound indices at the end of the parent scope,
+        // not including any parent `impl Trait`s.
+        let mut bound_vars = FxIndexMap::default();
+        debug!(?opaque.generics.params);
+        for param in opaque.generics.params {
+            let (def_id, reg) = ResolvedArg::early(param);
+            bound_vars.insert(def_id, reg);
+        }
+
+        let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id);
+        let scope = Scope::Binder {
+            hir_id,
+            bound_vars,
+            s: self.scope,
+            scope_type: BinderScopeType::Normal,
+            where_bound_origin: None,
+        };
+        self.with(scope, |this| {
+            let scope = Scope::TraitRefBoundary { s: this.scope };
+            this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
+        })
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match &item.kind {
             hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
@@ -513,38 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 // These sorts of items have no lifetime parameters at all.
                 intravisit::walk_item(self, item);
             }
-            hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
-                origin:
-                    hir::OpaqueTyOrigin::FnReturn(parent)
-                    | hir::OpaqueTyOrigin::AsyncFn(parent)
-                    | hir::OpaqueTyOrigin::TyAlias { parent, .. },
-                generics,
-                ..
-            }) => {
-                // We want to start our early-bound indices at the end of the parent scope,
-                // not including any parent `impl Trait`s.
-                let mut bound_vars = FxIndexMap::default();
-                debug!(?generics.params);
-                for param in generics.params {
-                    let (def_id, reg) = ResolvedArg::early(param);
-                    bound_vars.insert(def_id, reg);
-                }
-
-                let scope = Scope::Root { opt_parent_item: Some(parent) };
-                self.with(scope, |this| {
-                    let scope = Scope::Binder {
-                        hir_id: item.hir_id(),
-                        bound_vars,
-                        s: this.scope,
-                        scope_type: BinderScopeType::Normal,
-                        where_bound_origin: None,
-                    };
-                    this.with(scope, |this| {
-                        let scope = Scope::TraitRefBoundary { s: this.scope };
-                        this.with(scope, |this| intravisit::walk_item(this, item))
-                    });
-                })
-            }
             hir::ItemKind::TyAlias(_, generics)
             | hir::ItemKind::Const(_, generics, _)
             | hir::ItemKind::Enum(_, generics)
@@ -684,22 +676,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             hir::TyKind::Ref(lifetime_ref, ref mt) => {
                 self.visit_lifetime(lifetime_ref);
                 let scope = Scope::ObjectLifetimeDefault {
-                    lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
+                    lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
                     s: self.scope,
                 };
                 self.with(scope, |this| this.visit_ty(mt.ty));
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
+            hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
+                self.visit_opaque_ty(opaque_ty);
+
                 // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
                 // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
                 // `type MyAnonTy<'b> = impl MyTrait<'b>;`
                 //                 ^                  ^ this gets resolved in the scope of
                 //                                      the opaque_ty generics
-                let opaque_ty = self.tcx.hir().item(item_id);
-                match &opaque_ty.kind {
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {}
-                    i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
-                };
 
                 // Resolve the lifetimes that are applied to the opaque type.
                 // These are resolved in the current scope.
@@ -714,7 +703,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     // and ban them. Type variables instantiated inside binders aren't
                     // well-supported at the moment, so this doesn't work.
                     // In the future, this should be fixed and this error should be removed.
-                    let def = self.map.defs.get(&lifetime.hir_id).copied();
+                    let def = self.map.defs.get(&lifetime.hir_id.local_id).copied();
                     let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
                     let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
 
@@ -722,9 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     {
                         // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
                         // it must be a reified late-bound lifetime from a trait goal.
-                        hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::OpaqueTy { .. }, ..
-                        }) => "higher-ranked lifetime from outer `impl Trait`",
+                        hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`",
                         // Other items are fine.
                         hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
                             continue;
@@ -740,8 +727,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
                     let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
                     {
-                        let opaque_span = self.tcx.def_span(item_id.owner_id);
-                        (opaque_span, Some(opaque_span))
+                        (opaque_ty.span, Some(opaque_ty.span))
                     } else {
                         (lifetime.ident.span, None)
                     };
@@ -854,7 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             let bound_vars: Vec<_> =
                 self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
             let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
-            self.map.late_bound_vars.insert(hir_id, bound_vars);
+            self.map.late_bound_vars.insert(hir_id.local_id, bound_vars);
         }
         self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
         intravisit::walk_fn_kind(self, fk);
@@ -1032,10 +1018,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     }
 
     fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
-        if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
+        if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) {
             bug!(
                 "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
-                self.map.late_bound_vars[&hir_id]
+                self.map.late_bound_vars[&hir_id.local_id]
             )
         }
     }
@@ -1394,9 +1380,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         kind.descr(param_def_id.to_def_id())
                     ),
                 };
-                self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
+                self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
             } else {
-                self.map.defs.insert(hir_id, def);
+                self.map.defs.insert(hir_id.local_id, def);
             }
             return;
         }
@@ -1429,7 +1415,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                             bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
                         }
                     });
-                    self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
+                    self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar));
                     return;
                 }
                 Scope::Root { .. } => break,
@@ -1539,7 +1525,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     // This index can be used with `generic_args` since `parent_count == 0`.
                     let index = generics.param_def_id_to_index[&param_def_id] as usize;
                     generic_args.args.get(index).and_then(|arg| match arg {
-                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id).copied(),
+                        GenericArg::Lifetime(lt) => map.defs.get(&lt.hir_id.local_id).copied(),
                         _ => None,
                     })
                 }
@@ -1829,7 +1815,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
         debug!(span = ?lifetime_ref.ident.span);
-        self.map.defs.insert(lifetime_ref.hir_id, def);
+        self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
     }
 
     /// Sometimes we resolve a lifetime, but later find that it is an
@@ -1840,8 +1826,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         lifetime_ref: &'tcx hir::Lifetime,
         bad_def: ResolvedArg,
     ) {
-        // FIXME(#120456) - is `swap_remove` correct?
-        let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id);
+        let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id);
         assert_eq!(old_value, Some(bad_def));
     }
 
@@ -2011,7 +1996,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
         // And this is exercised in:
         // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
-        let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap();
+        let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap();
         let existing_bound_vars_saved = existing_bound_vars.clone();
         existing_bound_vars.extend(bound_vars);
         self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 48b5e87cbd0..470bcaeded1 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -529,10 +529,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
                 Ty::new_adt(tcx, def, args)
             }
-            ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
-                |CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
-                |ty| ty.instantiate_identity(),
-            ),
             ItemKind::Trait(..)
             | ItemKind::TraitAlias(..)
             | ItemKind::Macro(..)
@@ -545,6 +541,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
             }
         },
 
+        Node::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
+            |CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
+            |ty| ty.instantiate_identity(),
+        ),
+
         Node::ForeignItem(foreign_item) => match foreign_item.kind {
             ForeignItemKind::Fn(..) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
@@ -603,40 +604,25 @@ pub(super) fn type_of_opaque(
     def_id: DefId,
 ) -> Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
     if let Some(def_id) = def_id.as_local() {
-        use rustc_hir::*;
-
-        Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
-            Node::Item(item) => match item.kind {
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. },
-                    ..
-                }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
-                ItemKind::OpaqueTy(OpaqueTy {
-                    origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. },
-                    ..
-                }) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
-                // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(&OpaqueTy {
-                    origin:
-                        hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
-                    in_trait,
-                    ..
-                }) => {
-                    if in_trait && !tcx.defaultness(owner).has_value() {
-                        span_bug!(
-                            tcx.def_span(def_id),
-                            "tried to get type of this RPITIT with no definition"
-                        );
-                    }
-                    opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
-                }
-                _ => {
-                    span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
+        Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
+            hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
+                opaque::find_opaque_ty_constraints_for_tait(tcx, def_id)
+            }
+            hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
+                opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id)
+            }
+            // Opaque types desugared from `impl Trait`.
+            hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
+            | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
+                if in_trait_or_impl == Some(hir::RpitContext::Trait)
+                    && !tcx.defaultness(owner).has_value()
+                {
+                    span_bug!(
+                        tcx.def_span(def_id),
+                        "tried to get type of this RPITIT with no definition"
+                    );
                 }
-            },
-
-            x => {
-                bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
+                opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
             }
         }))
     } else {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index e7b8e6e69b0..394a263fbb5 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::{
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
+use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
 use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
 
@@ -124,16 +125,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .into_iter()
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
-        for (base_trait_ref, span) in regular_traits_refs_spans {
+        for (base_trait_ref, original_span) in regular_traits_refs_spans {
             let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
-            for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
+            for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in
+                traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
+                    .filter_only_self()
+            {
                 debug!("observing object predicate `{pred:?}`");
 
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
                         let pred = bound_predicate.rebind(pred);
-                        associated_types.entry(span).or_default().extend(
+                        associated_types.entry(original_span).or_default().extend(
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
                                 .filter(|item| item.kind == ty::AssocKind::Type)
@@ -172,8 +176,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // the discussion in #56288 for alternatives.
                         if !references_self {
                             // Include projections defined on supertraits.
-                            projection_bounds.push((pred, span));
+                            projection_bounds.push((pred, original_span));
                         }
+
+                        self.check_elaborated_projection_mentions_input_lifetimes(
+                            pred,
+                            original_span,
+                            supertrait_span,
+                        );
                     }
                     _ => (),
                 }
@@ -360,6 +370,56 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
     }
+
+    /// Check that elaborating the principal of a trait ref doesn't lead to projections
+    /// that are unconstrained. This can happen because an otherwise unconstrained
+    /// *type variable* can be substituted with a type that has late-bound regions. See
+    /// `elaborated-predicates-unconstrained-late-bound.rs` for a test.
+    fn check_elaborated_projection_mentions_input_lifetimes(
+        &self,
+        pred: ty::PolyProjectionPredicate<'tcx>,
+        span: Span,
+        supertrait_span: Span,
+    ) {
+        let tcx = self.tcx();
+
+        // Find any late-bound regions declared in `ty` that are not
+        // declared in the trait-ref or assoc_item. These are not well-formed.
+        //
+        // Example:
+        //
+        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+        let late_bound_in_projection_term =
+            tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
+        let late_bound_in_term =
+            tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
+        debug!(?late_bound_in_projection_term);
+        debug!(?late_bound_in_term);
+
+        // FIXME: point at the type params that don't have appropriate lifetimes:
+        // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+        //                         ----  ----     ^^^^^^^
+        // NOTE(associated_const_equality): This error should be impossible to trigger
+        //                                  with associated const equality constraints.
+        self.validate_late_bound_regions(
+            late_bound_in_projection_term,
+            late_bound_in_term,
+            |br_name| {
+                let item_name = tcx.item_name(pred.projection_def_id());
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0582,
+                    "binding for associated type `{}` references {}, \
+                             which does not appear in the trait input types",
+                    item_name,
+                    br_name
+                )
+                .with_span_label(supertrait_span, "due to this supertrait")
+            },
+        );
+    }
 }
 
 fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
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 a70f881f5fe..5607fe873f6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -108,17 +108,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let tcx = self.tcx();
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
         if let hir::Node::Item(hir::Item {
-            kind:
-                hir::ItemKind::Impl(hir::Impl {
-                    self_ty: impl_self_ty,
-                    of_trait: Some(of_trait_ref),
-                    generics,
-                    ..
-                }),
+            kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
             ..
         }) = tcx.hir_node_by_def_id(parent_id)
             && self_ty.hir_id == impl_self_ty.hir_id
         {
+            let Some(of_trait_ref) = of_trait else {
+                diag.span_suggestion_verbose(
+                    impl_self_ty.span.shrink_to_hi(),
+                    "you might have intended to implement this trait for a given type",
+                    format!(" for /* Type */"),
+                    Applicability::HasPlaceholders,
+                );
+                return;
+            };
             if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
                 return;
             }
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 6dd3a06ef37..28a1fc88741 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2087,23 +2087,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
                 self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
             }
-            &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
-                let opaque_ty = tcx.hir().item(item_id);
-
-                match opaque_ty.kind {
-                    hir::ItemKind::OpaqueTy(&hir::OpaqueTy { .. }) => {
-                        let local_def_id = item_id.owner_id.def_id;
-                        // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
-                        // generate the def_id of an associated type for the trait and return as
-                        // type a projection.
-                        let def_id = if in_trait {
-                            tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id()
-                        } else {
-                            local_def_id.to_def_id()
-                        };
-                        self.lower_opaque_ty(def_id, lifetimes, in_trait)
+            &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
+                let local_def_id = opaque_ty.def_id;
+
+                // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
+                // generate the def_id of an associated type for the trait and return as
+                // type a projection.
+                match opaque_ty.origin {
+                    hir::OpaqueTyOrigin::FnReturn {
+                        in_trait_or_impl: Some(hir::RpitContext::Trait),
+                        ..
+                    }
+                    | hir::OpaqueTyOrigin::AsyncFn {
+                        in_trait_or_impl: Some(hir::RpitContext::Trait),
+                        ..
+                    } => self.lower_opaque_ty(
+                        tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(),
+                        lifetimes,
+                        true,
+                    ),
+                    hir::OpaqueTyOrigin::FnReturn {
+                        in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                        ..
+                    }
+                    | hir::OpaqueTyOrigin::AsyncFn {
+                        in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                        ..
+                    }
+                    | hir::OpaqueTyOrigin::TyAlias { .. } => {
+                        self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false)
                     }
-                    ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
             // If we encounter a type relative path with RTN generics, then it must have
@@ -2269,7 +2282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     span_bug!(
                         tcx.def_span(param.def_id),
                         "only expected lifetime for opaque's own generics, got {:?}",
-                        param.kind
+                        param
                     );
                 };
                 let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 7d40a7746b9..71ee77f8f61 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -62,7 +62,6 @@ This API is completely unstable and subject to change.
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
-#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs
index dbaf9c2c6f0..a0fdf95a831 100644
--- a/compiler/rustc_hir_analysis/src/variance/dump.rs
+++ b/compiler/rustc_hir_analysis/src/variance/dump.rs
@@ -1,6 +1,5 @@
 use std::fmt::Write;
 
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_middle::ty::{GenericArgs, TyCtxt};
 use rustc_span::symbol::sym;
@@ -24,18 +23,18 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
 }
 
 pub(crate) fn variances(tcx: TyCtxt<'_>) {
-    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
-        for id in tcx.hir().items() {
-            let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
+    let crate_items = tcx.hir_crate_items(());
 
+    if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
+        for id in crate_items.opaques() {
             tcx.dcx().emit_err(crate::errors::VariancesOf {
-                span: tcx.def_span(id.owner_id),
-                variances: format_variances(tcx, id.owner_id.def_id),
+                span: tcx.def_span(id),
+                variances: format_variances(tcx, id),
             });
         }
     }
 
-    for id in tcx.hir().items() {
+    for id in crate_items.free_items() {
         if !tcx.has_attr(id.owner_id, sym::rustc_variance) {
             continue;
         }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1c52283d537..9fe6a8ee342 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -96,6 +96,7 @@ impl<'a> State<'a> {
             Node::Ty(a) => self.print_type(a),
             Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a),
             Node::TraitRef(a) => self.print_trait_ref(a),
+            Node::OpaqueTy(o) => self.print_opaque_ty(o),
             Node::Pat(a) => self.print_pat(a),
             Node::PatField(a) => self.print_patfield(a),
             Node::Arm(a) => self.print_arm(a),
@@ -568,11 +569,6 @@ impl<'a> State<'a> {
                     state.print_type(ty);
                 });
             }
-            hir::ItemKind::OpaqueTy(opaque_ty) => {
-                self.print_item_type(item, opaque_ty.generics, |state| {
-                    state.print_bounds("= impl", opaque_ty.bounds)
-                });
-            }
             hir::ItemKind::Enum(ref enum_definition, params) => {
                 self.print_enum_def(enum_definition, params, item.ident.name, item.span);
             }
@@ -665,6 +661,15 @@ impl<'a> State<'a> {
         self.print_path(t.path, false);
     }
 
+    fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) {
+        self.head("opaque");
+        self.print_generic_params(o.generics.params);
+        self.print_where_clause(o.generics);
+        self.word("{");
+        self.print_bounds("impl", o.bounds);
+        self.word("}");
+    }
+
     fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) {
         if !generic_params.is_empty() {
             self.word("for");
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 39d430cf73b..3669100ed91 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -23,17 +23,17 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
 
 hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
 
-hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+hir_typeck_cast_thin_pointer_to_wide_pointer = cannot cast thin pointer `{$expr_ty}` to wide pointer `{$cast_ty}`
     .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a
         memory address.
 
-        Fat pointers are pointers referencing "Dynamically Sized Types" (also
+        Wide pointers are pointers referencing "Dynamically Sized Types" (also
         called DST). DST don't have a statically known size, therefore they can
         only exist behind some kind of pointers that contain additional
         information. Slices and trait objects are DSTs. In the case of slices,
-        the additional information the fat pointer holds is their size.
+        the additional information the wide pointer holds is their size.
 
-        To fix this error, don't try to cast directly between thin and fat
+        To fix this error, don't try to cast directly between thin and wide
         pointers.
 
         For more information about casts, take a look at The Book:
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index bf8ed017cf7..0d9d1910ae0 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug", ret)]
-    pub fn check_match(
+    pub(crate) fn check_match(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         scrut: &'tcx hir::Expr<'tcx>,
@@ -602,7 +602,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .map(|(k, _)| (k.def_id, k.args))?,
             _ => return None,
         };
-        let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = self.tcx.opaque_type_origin(def_id)
+        let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id, .. } =
+            self.tcx.opaque_type_origin(def_id)
         else {
             return None;
         };
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index fcd2940b83a..407191661a4 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -66,7 +66,7 @@ pub(crate) struct CastCheck<'tcx> {
 }
 
 /// The kind of pointer and associated metadata (thin, length or vtable) - we
-/// only allow casts between fat pointers if their metadata have the same
+/// only allow casts between wide pointers if their metadata have the same
 /// kind.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
 enum PointerKind<'tcx> {
@@ -162,7 +162,7 @@ enum CastError<'tcx> {
         src_kind: PointerKind<'tcx>,
         dst_kind: PointerKind<'tcx>,
     },
-    /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
+    /// Cast of thin to wide raw ptr (e.g., `*const () as *const [u8]`).
     SizedUnsizedCast,
     IllegalCast,
     NeedDeref,
@@ -172,12 +172,12 @@ enum CastError<'tcx> {
     NonScalar,
     UnknownExprPtrKind,
     UnknownCastPtrKind,
-    /// Cast of int to (possibly) fat raw pointer.
+    /// Cast of int to (possibly) wide raw pointer.
     ///
     /// Argument is the specific name of the metadata in plain words, such as "a vtable"
     /// or "a length". If this argument is None, then the metadata is unknown, for example,
     /// when we're typechecking a type parameter with a ?Sized bound.
-    IntToFatCast(Option<&'static str>),
+    IntToWideCast(Option<&'static str>),
     ForeignNonExhaustiveAdt,
 }
 
@@ -545,14 +545,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
-                fcx.dcx().emit_err(errors::CastThinPointerToFatPointer {
+                fcx.dcx().emit_err(errors::CastThinPointerToWidePointer {
                     span: self.span,
                     expr_ty: self.expr_ty,
                     cast_ty: fcx.ty_to_string(self.cast_ty),
                     teach: fcx.tcx.sess.teach(E0607),
                 });
             }
-            CastError::IntToFatCast(known_metadata) => {
+            CastError::IntToWideCast(known_metadata) => {
                 let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
                 let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
                 let expr_ty = fcx.ty_to_string(self.expr_ty);
@@ -671,7 +671,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     #[instrument(skip(fcx), level = "debug")]
-    pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
+    pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
         self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty);
         self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty);
 
@@ -861,7 +861,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             return Ok(CastKind::PtrPtrCast);
         }
 
-        // We can't cast to fat pointer if source pointer kind is unknown
+        // We can't cast to wide pointer if source pointer kind is unknown
         let Some(src_kind) = src_kind else {
             return Err(CastError::UnknownCastPtrKind);
         };
@@ -1054,10 +1054,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
-            Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
-            Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
+            Some(PointerKind::VTable(_)) => Err(CastError::IntToWideCast(Some("a vtable"))),
+            Some(PointerKind::Length) => Err(CastError::IntToWideCast(Some("a length"))),
             Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => {
-                Err(CastError::IntToFatCast(None))
+                Err(CastError::IntToWideCast(None))
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 3e7ce2955fc..fcaa5751152 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -44,7 +44,7 @@ struct ClosureSignatures<'tcx> {
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self, closure), level = "debug")]
-    pub fn check_expr_closure(
+    pub(crate) fn check_expr_closure(
         &self,
         closure: &hir::Closure<'tcx>,
         expr_span: Span,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index cfa8fc4bbf2..777248ff873 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub fn demand_suptype_with_origin(
+    pub(crate) fn demand_suptype_with_origin(
         &'a self,
         cause: &ObligationCause<'tcx>,
         expected: Ty<'tcx>,
@@ -247,7 +247,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
     /// will be permitted if the diverges flag is currently "always".
     #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
-    pub fn demand_coerce_diag(
+    pub(crate) fn demand_coerce_diag(
         &'a self,
         mut expr: &'tcx hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index a692642ccfc..cceaabaff65 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -699,8 +699,8 @@ pub(crate) struct ReplaceWithName {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)]
-pub(crate) struct CastThinPointerToFatPointer<'tcx> {
+#[diag(hir_typeck_cast_thin_pointer_to_wide_pointer, code = E0607)]
+pub(crate) struct CastThinPointerToWidePointer<'tcx> {
     #[primary_span]
     pub span: Span,
     pub expr_ty: Ty<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index 67f4dbee3cb..4653458b5dd 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
     /// be checked higher up, as is the case with `&expr` and `box expr`), but
     /// is useful in determining the concrete type.
     ///
-    /// The primary use case is where the expected type is a fat pointer,
+    /// The primary use case is where the expected type is a wide pointer,
     /// like `&[isize]`. For example, consider the following statement:
     ///
     ///    let x: &[isize] = &[1, 2, 3];
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index b34ed4640db..e3c7dded0ca 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
                     if oprnd.is_syntactic_place_expr() {
                         // Places may legitimately have unsized types.
-                        // For example, dereferences of a fat pointer and
+                        // For example, dereferences of a wide pointer and
                         // the last field of a struct can be unsized.
                         ExpectHasType(*ty)
                     } else {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 62107877283..380d9126964 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -187,7 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn write_method_call_and_enforce_effects(
+    pub(crate) fn write_method_call_and_enforce_effects(
         &self,
         hir_id: HirId,
         span: Span,
@@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// occurred**, so that annotations like `Vec<_>` are preserved
     /// properly.
     #[instrument(skip(self), level = "debug")]
-    pub fn write_user_type_annotation_from_args(
+    pub(crate) fn write_user_type_annotation_from_args(
         &self,
         hir_id: HirId,
         def_id: DefId,
@@ -235,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    pub fn write_user_type_annotation(
+    pub(crate) fn write_user_type_annotation(
         &self,
         hir_id: HirId,
         canonical_user_type_annotation: CanonicalUserType<'tcx>,
@@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self, expr), level = "debug")]
-    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
+    pub(crate) fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
         debug!("expr = {:#?}", expr);
 
         if adj.is_empty() {
@@ -448,7 +448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip_all)]
-    pub fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+    pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.lower_ty(hir_ty);
         debug!(?ty);
 
@@ -736,7 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Resolves an associated value path into a base type and associated constant, or method
     /// resolution. The newly resolved definition is written into `type_dependent_defs`.
     #[instrument(level = "trace", skip(self), ret)]
-    pub fn resolve_ty_and_res_fully_qualified_call(
+    pub(crate) fn resolve_ty_and_res_fully_qualified_call(
         &self,
         qpath: &'tcx QPath<'tcx>,
         hir_id: HirId,
@@ -995,7 +995,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     #[instrument(skip(self, span), level = "debug")]
-    pub fn instantiate_value_path(
+    pub(crate) fn instantiate_value_path(
         &self,
         segments: &'tcx [hir::PathSegment<'tcx>],
         self_ty: Option<LoweredTy<'tcx>>,
@@ -1446,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// variable. This is different from `structurally_resolve_type` which errors
     /// in this case.
     #[instrument(level = "debug", skip(self, sp), ret)]
-    pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+    pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.resolve_vars_with_obligations(ty);
 
         if self.next_trait_solver()
@@ -1471,7 +1471,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self, sp), ret)]
-    pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    pub(crate) fn try_structurally_resolve_const(
+        &self,
+        sp: Span,
+        ct: ty::Const<'tcx>,
+    ) -> ty::Const<'tcx> {
         // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var.
 
         if self.next_trait_solver()
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 550c58b5a17..fa471647d02 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -984,7 +984,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             self.suggest_deref_unwrap_or(
                 &mut err,
-                error_span,
                 callee_ty,
                 call_ident,
                 expected_ty,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 487cc7e55cd..435b7d0f39a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -847,11 +847,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return true;
             }
             hir::FnRetTy::Return(hir_ty) => {
-                if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
+                if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
                     // FIXME: account for RPITIT.
-                    && let hir::Node::Item(hir::Item {
-                        kind: hir::ItemKind::OpaqueTy(op_ty), ..
-                    }) = self.tcx.hir_node(item_id.hir_id())
                     && let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds
                     && let Some(hir::PathSegment { args: Some(generic_args), .. }) =
                         trait_ref.trait_ref.path.segments.last()
@@ -1462,7 +1459,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn suggest_deref_unwrap_or(
         &self,
         err: &mut Diag<'_>,
-        error_span: Span,
         callee_ty: Option<Ty<'tcx>>,
         call_ident: Option<Ident>,
         expected_ty: Ty<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index f8352d9d44a..6b0a897faba 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -3,7 +3,6 @@
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(array_windows)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(never_type)]
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 72842075fec..1d7b3433fe5 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -235,6 +235,23 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     target,
                 });
             }
+
+            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
+                let region = self.next_region_var(infer::Autoref(self.span));
+
+                target = match target.kind() {
+                    ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
+                        let inner_ty = match args[0].expect_ty().kind() {
+                            ty::Ref(_, ty, _) => *ty,
+                            _ => bug!("Expected a reference type for argument to Pin"),
+                        };
+                        Ty::new_pinned_ref(self.tcx, region, inner_ty, mutbl)
+                    }
+                    _ => bug!("Cannot adjust receiver type for reborrowing pin of {target:?}"),
+                };
+
+                adjustments.push(Adjustment { kind: Adjust::ReborrowPin(region, mutbl), target });
+            }
             None => {}
         }
 
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 586b753f454..cb8b1df2c6e 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -18,8 +18,8 @@ use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_span::Span;
 use rustc_span::symbol::Ident;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, NormalizeExt};
 use tracing::{debug, instrument};
@@ -46,17 +46,17 @@ pub(crate) struct MethodCallee<'tcx> {
 
 #[derive(Debug)]
 pub(crate) enum MethodError<'tcx> {
-    // Did not find an applicable method, but we did find various near-misses that may work.
+    /// Did not find an applicable method, but we did find various near-misses that may work.
     NoMatch(NoMatchData<'tcx>),
 
-    // Multiple methods might apply.
+    /// Multiple methods might apply.
     Ambiguity(Vec<CandidateSource>),
 
-    // Found an applicable method, but it is not visible. The third argument contains a list of
-    // not-in-scope traits which may work.
+    /// Found an applicable method, but it is not visible. The third argument contains a list of
+    /// not-in-scope traits which may work.
     PrivateMatch(DefKind, DefId, Vec<DefId>),
 
-    // Found a `Self: Sized` bound where `Self` is a trait object.
+    /// Found a `Self: Sized` bound where `Self` is a trait object.
     IllegalSizedBound {
         candidates: Vec<DefId>,
         needs_mut: bool,
@@ -64,8 +64,11 @@ pub(crate) enum MethodError<'tcx> {
         self_expr: &'tcx hir::Expr<'tcx>,
     },
 
-    // Found a match, but the return type is wrong
+    /// Found a match, but the return type is wrong
     BadReturnType,
+
+    /// Error has already been emitted, no need to emit another one.
+    ErrorReported(ErrorGuaranteed),
 }
 
 // Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
@@ -91,7 +94,7 @@ pub(crate) enum CandidateSource {
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
     #[instrument(level = "debug", skip(self))]
-    pub fn method_exists_for_diagnostic(
+    pub(crate) fn method_exists_for_diagnostic(
         &self,
         method_name: Ident,
         self_ty: Ty<'tcx>,
@@ -120,6 +123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Err(PrivateMatch(..)) => false,
             Err(IllegalSizedBound { .. }) => true,
             Err(BadReturnType) => false,
+            Err(ErrorReported(_)) => false,
         }
     }
 
@@ -174,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// * `self_expr`:             the self expression (`foo`)
     /// * `args`:                  the expressions of the arguments (`a, b + 1, ...`)
     #[instrument(level = "debug", skip(self))]
-    pub fn lookup_method(
+    pub(crate) fn lookup_method(
         &self,
         self_ty: Ty<'tcx>,
         segment: &'tcx hir::PathSegment<'tcx>,
@@ -277,7 +281,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self, call_expr))]
-    pub fn lookup_probe(
+    pub(crate) fn lookup_probe(
         &self,
         method_name: Ident,
         self_ty: Ty<'tcx>,
@@ -494,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// * `self_ty_span`           the span for the type being searched within (span of `Foo`)
     /// * `expr_id`:               the [`hir::HirId`] of the expression composing the entire call
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn resolve_fully_qualified_call(
+    pub(crate) fn resolve_fully_qualified_call(
         &self,
         span: Span,
         method_name: Ident,
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 a8b5b6165db..b20592c85d2 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -121,16 +121,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             mutbl.ref_prefix_str()
                         }
                         Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+                        Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
+                            hir::Mutability::Mut => "Pin<&mut ",
+                            hir::Mutability::Not => "Pin<&",
+                        },
                     };
                     if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                     {
-                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                        let mut self_adjusted =
+                            if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+                                pick.autoref_or_ptr_adjustment
+                            {
+                                format!("{derefs}{self_expr} as *const _")
+                            } else {
+                                format!("{autoref}{derefs}{self_expr}")
+                            };
+
+                        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) =
                             pick.autoref_or_ptr_adjustment
                         {
-                            format!("{derefs}{self_expr} as *const _")
-                        } else {
-                            format!("{autoref}{derefs}{self_expr}")
-                        };
+                            self_adjusted.push('>');
+                        }
 
                         lint.span_suggestion(
                             sp,
@@ -400,6 +411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let autoref = match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(),
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
+            Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl {
+                hir::Mutability::Mut => "Pin<&mut ",
+                hir::Mutability::Not => "Pin<&",
+            },
         };
 
         let (expr_text, precise) = if let Some(expr_text) = expr
@@ -412,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ("(..)".to_string(), false)
         };
 
-        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
+        let mut adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
             pick.autoref_or_ptr_adjustment
         {
             format!("{derefs}{expr_text} as *const _")
@@ -420,6 +435,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             format!("{autoref}{derefs}{expr_text}")
         };
 
+        if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = pick.autoref_or_ptr_adjustment
+        {
+            adjusted_text.push('>');
+        }
+
         (adjusted_text, precise)
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 371380e575d..ba6bfd3a5e9 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -136,7 +136,7 @@ enum ProbeResult {
 /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub(crate) enum AutorefOrPtrAdjustment {
-    /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
+    /// Receiver has type `T`, add `&` or `&mut` (if `T` is `mut`), and maybe also "unsize" it.
     /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
     Autoref {
         mutbl: hir::Mutability,
@@ -147,6 +147,9 @@ pub(crate) enum AutorefOrPtrAdjustment {
     },
     /// Receiver has type `*mut T`, convert to `*const T`
     ToConstPtr,
+
+    /// Reborrow a `Pin<&mut T>` or `Pin<&T>`.
+    ReborrowPin(hir::Mutability),
 }
 
 impl AutorefOrPtrAdjustment {
@@ -154,6 +157,7 @@ impl AutorefOrPtrAdjustment {
         match self {
             AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
             AutorefOrPtrAdjustment::ToConstPtr => false,
+            AutorefOrPtrAdjustment::ReborrowPin(_) => false,
         }
     }
 }
@@ -224,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// would use to decide if a method is a plausible fit for
     /// ambiguity purposes).
     #[instrument(level = "debug", skip(self, candidate_filter))]
-    pub fn probe_for_return_type_for_diagnostic(
+    pub(crate) fn probe_for_return_type_for_diagnostic(
         &self,
         span: Span,
         mode: Mode,
@@ -267,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn probe_for_name(
+    pub(crate) fn probe_for_name(
         &self,
         mode: Mode,
         item_name: Ident,
@@ -446,13 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => bug!("unexpected bad final type in method autoderef"),
                 };
                 self.demand_eqtype(span, ty, Ty::new_error(self.tcx, guar));
-                return Err(MethodError::NoMatch(NoMatchData {
-                    static_candidates: Vec::new(),
-                    unsatisfied_predicates: Vec::new(),
-                    out_of_scope_traits: Vec::new(),
-                    similar_candidate: None,
-                    mode,
-                }));
+                return Err(MethodError::ErrorReported(guar));
             }
         }
 
@@ -1109,6 +1107,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                 unstable_candidates.as_deref_mut(),
                             )
                         })
+                        .or_else(|| {
+                            self.pick_reborrow_pin_method(
+                                step,
+                                self_ty,
+                                unstable_candidates.as_deref_mut(),
+                            )
+                        })
                     })
             })
     }
@@ -1133,13 +1138,28 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
 
-                // Insert a `&*` or `&mut *` if this is a reference type:
-                if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
-                    pick.autoderefs += 1;
-                    pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
-                        mutbl,
-                        unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
-                    })
+                match *step.self_ty.value.value.kind() {
+                    // Insert a `&*` or `&mut *` if this is a reference type:
+                    ty::Ref(_, _, mutbl) => {
+                        pick.autoderefs += 1;
+                        pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
+                            mutbl,
+                            unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
+                        })
+                    }
+
+                    ty::Adt(def, args)
+                        if self.tcx.features().pin_ergonomics
+                            && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
+                    {
+                        // make sure this is a pinned reference (and not a `Pin<Box>` or something)
+                        if let ty::Ref(_, _, mutbl) = args[0].expect_ty().kind() {
+                            pick.autoref_or_ptr_adjustment =
+                                Some(AutorefOrPtrAdjustment::ReborrowPin(*mutbl));
+                        }
+                    }
+
+                    _ => (),
                 }
 
                 pick
@@ -1170,6 +1190,43 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         })
     }
 
+    /// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
+    #[instrument(level = "debug", skip(self, step, unstable_candidates))]
+    fn pick_reborrow_pin_method(
+        &self,
+        step: &CandidateStep<'tcx>,
+        self_ty: Ty<'tcx>,
+        unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
+    ) -> Option<PickResult<'tcx>> {
+        if !self.tcx.features().pin_ergonomics {
+            return None;
+        }
+
+        // make sure self is a Pin<&mut T>
+        let inner_ty = match self_ty.kind() {
+            ty::Adt(def, args) if self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => {
+                match args[0].expect_ty().kind() {
+                    ty::Ref(_, ty, hir::Mutability::Mut) => *ty,
+                    _ => {
+                        return None;
+                    }
+                }
+            }
+            _ => return None,
+        };
+
+        let region = self.tcx.lifetimes.re_erased;
+        let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
+        self.pick_method(autopin_ty, unstable_candidates).map(|r| {
+            r.map(|mut pick| {
+                pick.autoderefs = step.autoderefs;
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
+                pick
+            })
+        })
+    }
+
     /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
     /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
     /// autorefs would require dereferencing the pointer, which is not safe.
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e03be4f43f7..4f726f3ed38 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -183,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    pub fn report_method_error(
+    pub(crate) fn report_method_error(
         &self,
         call_id: HirId,
         rcvr_ty: Ty<'tcx>,
@@ -229,20 +229,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         match error {
-            MethodError::NoMatch(mut no_match_data) => {
-                return self.report_no_match_method_error(
-                    span,
-                    rcvr_ty,
-                    item_name,
-                    call_id,
-                    source,
-                    args,
-                    sugg_span,
-                    &mut no_match_data,
-                    expected,
-                    trait_missing_method,
-                );
-            }
+            MethodError::NoMatch(mut no_match_data) => self.report_no_match_method_error(
+                span,
+                rcvr_ty,
+                item_name,
+                call_id,
+                source,
+                args,
+                sugg_span,
+                &mut no_match_data,
+                expected,
+                trait_missing_method,
+            ),
 
             MethodError::Ambiguity(mut sources) => {
                 let mut err = struct_span_code_err!(
@@ -263,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     &mut sources,
                     Some(sugg_span),
                 );
-                return err.emit();
+                err.emit()
             }
 
             MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
@@ -284,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .unwrap_or_else(|| self.tcx.def_span(def_id));
                 err.span_label(sp, format!("private {kind} defined here"));
                 self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
-                return err.emit();
+                err.emit()
             }
 
             MethodError::IllegalSizedBound { candidates, needs_mut, bound_span, self_expr } => {
@@ -383,9 +381,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                 }
-                return err.emit();
+                err.emit()
             }
 
+            MethodError::ErrorReported(guar) => guar,
+
             MethodError::BadReturnType => bug!("no return type expectations but got BadReturnType"),
         }
     }
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 3b2ef3fe981..4a8c7387ddc 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -1,4 +1,4 @@
-//! There are four type combiners: [TypeRelating], [Lub], and [Glb],
+//! There are four type combiners: [TypeRelating], `Lub`, and `Glb`,
 //! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL.
 //!
 //! Each implements the trait [TypeRelation] and contains methods for
@@ -26,8 +26,7 @@ use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt,
 pub use rustc_next_trait_solver::relate::combine::*;
 use tracing::debug;
 
-use super::glb::Glb;
-use super::lub::Lub;
+use super::lattice::{LatticeOp, LatticeOpKind};
 use super::type_relating::TypeRelating;
 use super::{RelateResult, StructurallyRelateAliases};
 use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate};
@@ -303,12 +302,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant)
     }
 
-    pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> {
-        Lub::new(self)
+    pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> {
+        LatticeOp::new(self, LatticeOpKind::Lub)
     }
 
-    pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> {
-        Glb::new(self)
+    pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> {
+        LatticeOp::new(self, LatticeOpKind::Glb)
     }
 
     pub fn register_obligations(
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
deleted file mode 100644
index ed108f42969..00000000000
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-//! Greatest lower bound. See [`lattice`].
-
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
-use tracing::{debug, instrument};
-
-use super::StructurallyRelateAliases;
-use super::combine::{CombineFields, PredicateEmittingRelation};
-use super::lattice::{self, LatticeDir};
-use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
-use crate::traits::ObligationCause;
-
-/// "Greatest lower bound" (common subtype)
-pub struct Glb<'combine, 'infcx, 'tcx> {
-    fields: &'combine mut CombineFields<'infcx, 'tcx>,
-}
-
-impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> {
-    pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> {
-        Glb { fields }
-    }
-}
-
-impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
-    fn cx(&self) -> TyCtxt<'tcx> {
-        self.fields.tcx()
-    }
-
-    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
-        &mut self,
-        variance: ty::Variance,
-        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        match variance {
-            ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
-            ty::Covariant => self.relate(a, b),
-            // FIXME(#41044) -- not correct, need test
-            ty::Bivariant => Ok(a),
-            ty::Contravariant => self.fields.lub().relate(a, b),
-        }
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        lattice::super_lattice_tys(self, a, b)
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
-        // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
-            self.cx(),
-            origin,
-            a,
-            b,
-        ))
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<TyCtxt<'tcx>>,
-    {
-        // GLB of a binder and itself is just itself
-        if a == b {
-            return Ok(a);
-        }
-
-        debug!("binders(a={:?}, b={:?})", a, b);
-        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
-            // When higher-ranked types are involved, computing the GLB is
-            // very challenging, switch to invariance. This is obviously
-            // overly conservative but works ok in practice.
-            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
-            Ok(a)
-        } else {
-            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
-        }
-    }
-}
-
-impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> {
-    fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
-        self.fields.infcx
-    }
-
-    fn cause(&self) -> &ObligationCause<'tcx> {
-        &self.fields.trace.cause
-    }
-
-    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
-        let mut sub = self.fields.sub();
-        sub.relate(v, a)?;
-        sub.relate(v, b)?;
-        Ok(())
-    }
-
-    fn define_opaque_types(&self) -> DefineOpaqueTypes {
-        self.fields.define_opaque_types
-    }
-}
-
-impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> {
-    fn span(&self) -> Span {
-        self.fields.trace.span()
-    }
-
-    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
-        StructurallyRelateAliases::No
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.fields.param_env
-    }
-
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_predicates(obligations);
-    }
-
-    fn register_goals(
-        &mut self,
-        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_obligations(obligations);
-    }
-
-    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
-        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
-            a.into(),
-            b.into(),
-            // FIXME(deferred_projection_equality): This isn't right, I think?
-            ty::AliasRelationDirection::Equate,
-        ))]);
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index 1d3f45465d6..9564baa6ab2 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -17,99 +17,247 @@
 //!
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
-use rustc_middle::ty::relate::RelateResult;
-use rustc_middle::ty::{self, Ty, TyVar};
-use tracing::instrument;
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
+use rustc_span::Span;
+use tracing::{debug, instrument};
 
-use super::combine::PredicateEmittingRelation;
-use crate::infer::{DefineOpaqueTypes, InferCtxt};
-use crate::traits::ObligationCause;
+use super::StructurallyRelateAliases;
+use super::combine::{CombineFields, PredicateEmittingRelation};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
 
-/// Trait for returning data about a lattice, and for abstracting
-/// over the "direction" of the lattice operation (LUB/GLB).
-///
-/// GLB moves "down" the lattice (to smaller values); LUB moves
-/// "up" the lattice (to bigger values).
-pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
-    fn infcx(&self) -> &'f InferCtxt<'tcx>;
+#[derive(Clone, Copy)]
+pub(crate) enum LatticeOpKind {
+    Glb,
+    Lub,
+}
+
+impl LatticeOpKind {
+    fn invert(self) -> Self {
+        match self {
+            LatticeOpKind::Glb => LatticeOpKind::Lub,
+            LatticeOpKind::Lub => LatticeOpKind::Glb,
+        }
+    }
+}
+
+/// A greatest lower bound" (common subtype) or least upper bound (common supertype).
+pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> {
+    fields: &'combine mut CombineFields<'infcx, 'tcx>,
+    kind: LatticeOpKind,
+}
+
+impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> {
+    pub(crate) fn new(
+        fields: &'combine mut CombineFields<'infcx, 'tcx>,
+        kind: LatticeOpKind,
+    ) -> LatticeOp<'combine, 'infcx, 'tcx> {
+        LatticeOp { fields, kind }
+    }
+}
+
+impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.fields.tcx()
+    }
 
-    fn cause(&self) -> &ObligationCause<'tcx>;
+    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
+        &mut self,
+        variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
+        a: T,
+        b: T,
+    ) -> RelateResult<'tcx, T> {
+        match variance {
+            ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
+            ty::Covariant => self.relate(a, b),
+            // FIXME(#41044) -- not correct, need test
+            ty::Bivariant => Ok(a),
+            ty::Contravariant => {
+                self.kind = self.kind.invert();
+                let res = self.relate(a, b);
+                self.kind = self.kind.invert();
+                res
+            }
+        }
+    }
+
+    /// Relates two types using a given lattice.
+    #[instrument(skip(self), level = "trace")]
+    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        if a == b {
+            return Ok(a);
+        }
+
+        let infcx = self.fields.infcx;
+
+        let a = infcx.shallow_resolve(a);
+        let b = infcx.shallow_resolve(b);
+
+        match (a.kind(), b.kind()) {
+            // If one side is known to be a variable and one is not,
+            // create a variable (`v`) to represent the LUB. Make sure to
+            // relate `v` to the non-type-variable first (by passing it
+            // first to `relate_bound`). Otherwise, we would produce a
+            // subtype obligation that must then be processed.
+            //
+            // Example: if the LHS is a type variable, and RHS is
+            // `Box<i32>`, then we current compare `v` to the RHS first,
+            // which will instantiate `v` with `Box<i32>`. Then when `v`
+            // is compared to the LHS, we instantiate LHS with `Box<i32>`.
+            // But if we did in reverse order, we would create a `v <:
+            // LHS` (or vice versa) constraint and then instantiate
+            // `v`. This would require further processing to achieve same
+            // end-result; in particular, this screws up some of the logic
+            // in coercion, which expects LUB to figure out that the LHS
+            // is (e.g.) `Box<i32>`. A more obvious solution might be to
+            // iterate on the subtype obligations that are returned, but I
+            // think this suffices. -nmatsakis
+            (&ty::Infer(TyVar(..)), _) => {
+                let v = infcx.next_ty_var(self.fields.trace.cause.span);
+                self.relate_bound(v, b, a)?;
+                Ok(v)
+            }
+            (_, &ty::Infer(TyVar(..))) => {
+                let v = infcx.next_ty_var(self.fields.trace.cause.span);
+                self.relate_bound(v, a, b)?;
+                Ok(v)
+            }
+
+            (
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+                &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+            ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b),
+
+            (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+            | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
+                if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+                    && def_id.is_local()
+                    && !infcx.next_trait_solver() =>
+            {
+                self.register_goals(infcx.handle_opaque_type(
+                    a,
+                    b,
+                    self.span(),
+                    self.param_env(),
+                )?);
+                Ok(a)
+            }
+
+            _ => infcx.super_combine_tys(self, a, b),
+        }
+    }
 
-    fn define_opaque_types(&self) -> DefineOpaqueTypes;
+    #[instrument(skip(self), level = "trace")]
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
+        let mut inner = self.fields.infcx.inner.borrow_mut();
+        let mut constraints = inner.unwrap_region_constraints();
+        Ok(match self.kind {
+            // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
+            LatticeOpKind::Glb => constraints.lub_regions(self.cx(), origin, a, b),
 
+            // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
+            LatticeOpKind::Lub => constraints.glb_regions(self.cx(), origin, a, b),
+        })
+    }
+
+    #[instrument(skip(self), level = "trace")]
+    fn consts(
+        &mut self,
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        self.fields.infcx.super_combine_consts(self, a, b)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: ty::Binder<'tcx, T>,
+        b: ty::Binder<'tcx, T>,
+    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+    where
+        T: Relate<TyCtxt<'tcx>>,
+    {
+        // GLB/LUB of a binder and itself is just itself
+        if a == b {
+            return Ok(a);
+        }
+
+        debug!("binders(a={:?}, b={:?})", a, b);
+        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
+            // When higher-ranked types are involved, computing the GLB/LUB is
+            // very challenging, switch to invariance. This is obviously
+            // overly conservative but works ok in practice.
+            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
+            Ok(a)
+        } else {
+            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
+        }
+    }
+}
+
+impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> {
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
     //
     // Subtle hack: ordering *may* be significant here. This method
     // relates `v` to `a` first, which may help us to avoid unnecessary
     // type variable obligations. See caller for details.
-    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
+    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
+        let mut sub = self.fields.sub();
+        match self.kind {
+            LatticeOpKind::Glb => {
+                sub.relate(v, a)?;
+                sub.relate(v, b)?;
+            }
+            LatticeOpKind::Lub => {
+                sub.relate(a, v)?;
+                sub.relate(b, v)?;
+            }
+        }
+        Ok(())
+    }
 }
 
-/// Relates two types using a given lattice.
-#[instrument(skip(this), level = "debug")]
-pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
-    this: &mut L,
-    a: Ty<'tcx>,
-    b: Ty<'tcx>,
-) -> RelateResult<'tcx, Ty<'tcx>>
-where
-    L: LatticeDir<'a, 'tcx>,
-{
-    if a == b {
-        return Ok(a);
+impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> {
+    fn span(&self) -> Span {
+        self.fields.trace.span()
     }
 
-    let infcx = this.infcx();
-
-    let a = infcx.shallow_resolve(a);
-    let b = infcx.shallow_resolve(b);
-
-    match (a.kind(), b.kind()) {
-        // If one side is known to be a variable and one is not,
-        // create a variable (`v`) to represent the LUB. Make sure to
-        // relate `v` to the non-type-variable first (by passing it
-        // first to `relate_bound`). Otherwise, we would produce a
-        // subtype obligation that must then be processed.
-        //
-        // Example: if the LHS is a type variable, and RHS is
-        // `Box<i32>`, then we current compare `v` to the RHS first,
-        // which will instantiate `v` with `Box<i32>`. Then when `v`
-        // is compared to the LHS, we instantiate LHS with `Box<i32>`.
-        // But if we did in reverse order, we would create a `v <:
-        // LHS` (or vice versa) constraint and then instantiate
-        // `v`. This would require further processing to achieve same
-        // end-result; in particular, this screws up some of the logic
-        // in coercion, which expects LUB to figure out that the LHS
-        // is (e.g.) `Box<i32>`. A more obvious solution might be to
-        // iterate on the subtype obligations that are returned, but I
-        // think this suffices. -nmatsakis
-        (&ty::Infer(TyVar(..)), _) => {
-            let v = infcx.next_ty_var(this.cause().span);
-            this.relate_bound(v, b, a)?;
-            Ok(v)
-        }
-        (_, &ty::Infer(TyVar(..))) => {
-            let v = infcx.next_ty_var(this.cause().span);
-            this.relate_bound(v, a, b)?;
-            Ok(v)
-        }
+    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
+        StructurallyRelateAliases::No
+    }
 
-        (
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
-            &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
-        ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
-
-        (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
-        | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-            if this.define_opaque_types() == DefineOpaqueTypes::Yes
-                && def_id.is_local()
-                && !this.infcx().next_trait_solver() =>
-        {
-            this.register_goals(infcx.handle_opaque_type(a, b, this.span(), this.param_env())?);
-            Ok(a)
-        }
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.fields.param_env
+    }
+
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
+        self.fields.register_predicates(obligations);
+    }
+
+    fn register_goals(
+        &mut self,
+        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+    ) {
+        self.fields.register_obligations(obligations);
+    }
 
-        _ => infcx.super_combine_tys(this, a, b),
+    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
+            a.into(),
+            b.into(),
+            // FIXME(deferred_projection_equality): This isn't right, I think?
+            ty::AliasRelationDirection::Equate,
+        ))]);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
deleted file mode 100644
index 35c7ab5000d..00000000000
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! Least upper bound. See [`lattice`].
-
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
-use tracing::{debug, instrument};
-
-use super::StructurallyRelateAliases;
-use super::combine::{CombineFields, PredicateEmittingRelation};
-use super::lattice::{self, LatticeDir};
-use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
-use crate::traits::ObligationCause;
-
-/// "Least upper bound" (common supertype)
-pub struct Lub<'combine, 'infcx, 'tcx> {
-    fields: &'combine mut CombineFields<'infcx, 'tcx>,
-}
-
-impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> {
-    pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> {
-        Lub { fields }
-    }
-}
-
-impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
-    fn cx(&self) -> TyCtxt<'tcx> {
-        self.fields.tcx()
-    }
-
-    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
-        &mut self,
-        variance: ty::Variance,
-        _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        match variance {
-            ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
-            ty::Covariant => self.relate(a, b),
-            // FIXME(#41044) -- not correct, need test
-            ty::Bivariant => Ok(a),
-            ty::Contravariant => self.fields.glb().relate(a, b),
-        }
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        lattice::super_lattice_tys(self, a, b)
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
-        // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
-        Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
-            self.cx(),
-            origin,
-            a,
-            b,
-        ))
-    }
-
-    #[instrument(skip(self), level = "trace")]
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<TyCtxt<'tcx>>,
-    {
-        // LUB of a binder and itself is just itself
-        if a == b {
-            return Ok(a);
-        }
-
-        debug!("binders(a={:?}, b={:?})", a, b);
-        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
-            // When higher-ranked types are involved, computing the LUB is
-            // very challenging, switch to invariance. This is obviously
-            // overly conservative but works ok in practice.
-            self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
-            Ok(a)
-        } else {
-            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
-        }
-    }
-}
-
-impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
-    fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
-        self.fields.infcx
-    }
-
-    fn cause(&self) -> &ObligationCause<'tcx> {
-        &self.fields.trace.cause
-    }
-
-    fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
-        let mut sub = self.fields.sub();
-        sub.relate(a, v)?;
-        sub.relate(b, v)?;
-        Ok(())
-    }
-
-    fn define_opaque_types(&self) -> DefineOpaqueTypes {
-        self.fields.define_opaque_types
-    }
-}
-
-impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> {
-    fn span(&self) -> Span {
-        self.fields.trace.span()
-    }
-
-    fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
-        StructurallyRelateAliases::No
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.fields.param_env
-    }
-
-    fn register_predicates(
-        &mut self,
-        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_predicates(obligations);
-    }
-
-    fn register_goals(
-        &mut self,
-        obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) {
-        self.fields.register_obligations(obligations)
-    }
-
-    fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
-        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
-            a.into(),
-            b.into(),
-            // FIXME(deferred_projection_equality): This isn't right, I think?
-            ty::AliasRelationDirection::Equate,
-        ))]);
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs
index 183ea5b3309..edc0c4f078a 100644
--- a/compiler/rustc_infer/src/infer/relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/relate/mod.rs
@@ -10,8 +10,6 @@ pub use self::combine::{CombineFields, PredicateEmittingRelation};
 #[allow(hidden_glob_reexports)]
 pub(super) mod combine;
 mod generalize;
-mod glb;
 mod higher_ranked;
 mod lattice;
-mod lub;
 mod type_relating;
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 051bba58518..934484bf915 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -20,7 +20,6 @@
 #![doc(rust_logo)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(extend_one)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs
index d9040207300..63a8a949e96 100644
--- a/compiler/rustc_lint/src/async_fn_in_trait.rs
+++ b/compiler/rustc_lint/src/async_fn_in_trait.rs
@@ -104,8 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
                 return;
             }
 
-            let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
-                sig.decl.output
+            let hir::FnRetTy::Return(hir::Ty {
+                kind: hir::TyKind::OpaqueDef(opaq_def, ..), ..
+            }) = sig.decl.output
             else {
                 // This should never happen, but let's not ICE.
                 return;
@@ -114,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
                 cx.tcx,
                 sig,
                 body,
-                def.owner_id.def_id,
+                opaq_def.def_id,
                 " + Send",
             );
             cx.tcx.emit_node_span_lint(
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index a073d16f634..d029ad93407 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -258,9 +258,9 @@ where
             && self.seen.insert(opaque_def_id)
             // If it's owned by this function
             && let opaque =
-                self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty()
-            && let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
-            && parent_def_id == self.parent_def_id
+                self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty()
+            && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin
+            && parent == self.parent_def_id
         {
             let opaque_span = self.tcx.def_span(opaque_def_id);
             let new_capture_rules =
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c74cb866f21..e58ad23f414 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -32,7 +32,6 @@
 #![feature(array_windows)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
-#![feature(control_flow_enum)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
 #![feature(iter_order_by)]
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 0045cfcaa56..8467c416f4a 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1703,7 +1703,7 @@ pub(crate) enum InvalidNanComparisons {
     #[diag(lint_invalid_nan_comparisons_eq_ne)]
     EqNe {
         #[subdiagnostic]
-        suggestion: Option<InvalidNanComparisonsSuggestion>,
+        suggestion: InvalidNanComparisonsSuggestion,
     },
     #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)]
     LtLeGtGe,
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 83652bbf546..ffbcf7f808e 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -68,8 +68,8 @@ declare_lint! {
 declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        let hir::ItemKind::OpaqueTy(opaque) = &item.kind else {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) {
+        let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else {
             return;
         };
 
@@ -77,14 +77,14 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
         // That's because although we may have an opaque type on the function,
         // it won't have a hidden type, so proving predicates about it is
         // not really meaningful.
-        if let hir::OpaqueTyOrigin::FnReturn(method_def_id) = opaque.origin
+        if let hir::OpaqueTyOrigin::FnReturn { parent: method_def_id, .. } = opaque.origin
             && let hir::Node::TraitItem(trait_item) = cx.tcx.hir_node_by_def_id(method_def_id)
             && !trait_item.defaultness.has_value()
         {
             return;
         }
 
-        let def_id = item.owner_id.def_id.to_def_id();
+        let def_id = opaque.def_id.to_def_id();
         let infcx = &cx.tcx.infer_ctxt().build();
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                     && cx.tcx.parent(opaque_ty.def_id) == def_id
                     && matches!(
                         opaque.origin,
-                        hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
+                        hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. }
                     )
                 {
                     return;
@@ -114,8 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                 // return type is well-formed in traits even when `Self` isn't sized.
                 if let ty::Param(param_ty) = *proj_term.kind()
                     && param_ty.name == kw::SelfUpper
-                    && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_))
-                    && opaque.in_trait
+                    && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn {
+                        in_trait_or_impl: Some(hir::RpitContext::Trait),
+                        ..
+                    })
                 {
                     return;
                 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 15fe18adbfb..db4413149a4 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -209,36 +209,32 @@ fn lint_nan<'tcx>(
     }
 
     fn eq_ne(
-        cx: &LateContext<'_>,
         e: &hir::Expr<'_>,
         l: &hir::Expr<'_>,
         r: &hir::Expr<'_>,
         f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion,
     ) -> InvalidNanComparisons {
-        // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const.
-        let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| {
-            if let Some(l_span) = l.span.find_ancestor_inside(e.span)
-                && let Some(r_span) = r.span.find_ancestor_inside(e.span)
-            {
-                f(l_span, r_span)
-            } else {
-                InvalidNanComparisonsSuggestion::Spanless
-            }
-        });
+        let suggestion = if let Some(l_span) = l.span.find_ancestor_inside(e.span)
+            && let Some(r_span) = r.span.find_ancestor_inside(e.span)
+        {
+            f(l_span, r_span)
+        } else {
+            InvalidNanComparisonsSuggestion::Spanless
+        };
 
         InvalidNanComparisons::EqNe { suggestion }
     }
 
     let lint = match binop.node {
         hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => {
-            eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
+            eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
                 nan_plus_binop: l_span.until(r_span),
                 float: r_span.shrink_to_hi(),
                 neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()),
             })
         }
         hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => {
-            eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
+            eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
                 nan_plus_binop: l_span.shrink_to_hi().to(r_span),
                 float: l_span.shrink_to_hi(),
                 neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()),
@@ -1423,7 +1419,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
             hir::ItemKind::Impl(..)
             | hir::ItemKind::TraitAlias(..)
             | hir::ItemKind::Trait(..)
-            | hir::ItemKind::OpaqueTy(..)
             | hir::ItemKind::GlobalAsm(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Mod(..)
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 10f2087d1e6..b817b4cb7b8 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,9 +1,7 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
-#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(control_flow_enum)]
 #![feature(coroutines)]
 #![feature(decl_macro)]
 #![feature(error_iter)]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 089ac060ba8..99c673b021a 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -218,7 +218,7 @@ use std::ops::Deref;
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt};
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owned_slice::slice_owned;
 use rustc_data_structures::svh::Svh;
@@ -385,7 +385,7 @@ impl<'a> CrateLocator<'a> {
         let dylib_suffix = &self.target.dll_suffix;
         let staticlib_suffix = &self.target.staticlib_suffix;
 
-        let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
+        let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> =
             Default::default();
 
         // First, find all possible candidate rlibs and dylibs purely based on
@@ -460,7 +460,7 @@ impl<'a> CrateLocator<'a> {
         // A Library candidate is created if the metadata for the set of
         // libraries corresponds to the crate id and hash criteria that this
         // search is being performed for.
-        let mut libraries = FxHashMap::default();
+        let mut libraries = FxIndexMap::default();
         for (_hash, (rlibs, rmetas, dylibs)) in candidates {
             if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
                 libraries.insert(svh, lib);
@@ -494,9 +494,9 @@ impl<'a> CrateLocator<'a> {
 
     fn extract_lib(
         &mut self,
-        rlibs: FxHashMap<PathBuf, PathKind>,
-        rmetas: FxHashMap<PathBuf, PathKind>,
-        dylibs: FxHashMap<PathBuf, PathKind>,
+        rlibs: FxIndexMap<PathBuf, PathKind>,
+        rmetas: FxIndexMap<PathBuf, PathKind>,
+        dylibs: FxIndexMap<PathBuf, PathKind>,
     ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
         // Order here matters, rmeta should come first. See comment in
@@ -534,7 +534,7 @@ impl<'a> CrateLocator<'a> {
     // The `PathBuf` in `slot` will only be used for diagnostic purposes.
     fn extract_one(
         &mut self,
-        m: FxHashMap<PathBuf, PathKind>,
+        m: FxIndexMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
         slot: &mut Option<(Svh, MetadataBlob, PathBuf)>,
     ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
@@ -702,9 +702,9 @@ impl<'a> CrateLocator<'a> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
-        let mut rlibs = FxHashMap::default();
-        let mut rmetas = FxHashMap::default();
-        let mut dylibs = FxHashMap::default();
+        let mut rlibs = FxIndexMap::default();
+        let mut rmetas = FxIndexMap::default();
+        let mut dylibs = FxIndexMap::default();
         for loc in &self.exact_paths {
             if !loc.canonicalized().exists() {
                 return Err(CrateError::ExternLocationNotExist(
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 82b907d2501..c7953d50406 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,7 +1,7 @@
 use std::ops::ControlFlow;
 use std::path::{Path, PathBuf};
 
-use rustc_ast::{CRATE_NODE_ID, NestedMetaItem};
+use rustc_ast::CRATE_NODE_ID;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::query::LocalCrate;
@@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
                             sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
                             continue;
                         };
-                        let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
+                        let [link_cfg] = link_cfg else {
+                            sess.dcx()
+                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
+                            continue;
+                        };
+                        let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
                             sess.dcx()
                                 .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
                             continue;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 5f756672b04..610c682d3a4 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1186,9 +1186,9 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
 
         DefKind::OpaqueTy => {
             let origin = tcx.opaque_type_origin(def_id);
-            if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
-            | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
-                && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
+            if let hir::OpaqueTyOrigin::FnReturn { parent, .. }
+            | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin
+                && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent)
                 && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
             {
                 false
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e11361a615f..8fd5ff1f369 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -732,6 +732,19 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    #[track_caller]
+    pub fn expect_opaque_ty(self, id: LocalDefId) -> &'hir OpaqueTy<'hir> {
+        match self.tcx.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))
+                )
+            }
+        }
+    }
+
     pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
         match self.tcx.hir_node(id) {
             Node::Expr(expr) => expr,
@@ -923,6 +936,7 @@ impl<'hir> Map<'hir> {
             Node::Ty(ty) => ty.span,
             Node::AssocItemConstraint(constraint) => constraint.span,
             Node::TraitRef(tr) => tr.path.span,
+            Node::OpaqueTy(op) => op.span,
             Node::Pat(pat) => pat.span,
             Node::PatField(field) => field.span,
             Node::Arm(arm) => arm.span,
@@ -1006,6 +1020,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> {
         self.tcx.hir_node(hir_id)
     }
 
+    fn hir_node_by_def_id(&self, def_id: LocalDefId) -> Node<'hir> {
+        self.tcx.hir_node_by_def_id(def_id)
+    }
+
     fn body(&self, id: BodyId) -> &'hir Body<'hir> {
         (*self).body(id)
     }
@@ -1139,13 +1157,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::ForeignMod { .. } => "foreign mod",
                 ItemKind::GlobalAsm(..) => "global asm",
                 ItemKind::TyAlias(..) => "ty",
-                ItemKind::OpaqueTy(opaque) => {
-                    if opaque.in_trait {
-                        "opaque type in trait"
-                    } else {
-                        "opaque type"
-                    }
-                }
                 ItemKind::Enum(..) => "enum",
                 ItemKind::Struct(..) => "struct",
                 ItemKind::Union(..) => "union",
@@ -1197,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         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::PatField(_) => node_str("pattern field"),
         Node::Param(_) => node_str("param"),
@@ -1234,6 +1246,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
         impl_items,
         foreign_items,
         body_owners,
+        opaques,
         ..
     } = collector;
     ModuleItems {
@@ -1243,6 +1256,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
         body_owners: body_owners.into_boxed_slice(),
+        opaques: opaques.into_boxed_slice(),
     }
 }
 
@@ -1262,6 +1276,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
         impl_items,
         foreign_items,
         body_owners,
+        opaques,
         ..
     } = collector;
 
@@ -1272,6 +1287,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
         body_owners: body_owners.into_boxed_slice(),
+        opaques: opaques.into_boxed_slice(),
     }
 }
 
@@ -1286,6 +1302,7 @@ struct ItemCollector<'tcx> {
     impl_items: Vec<ImplItemId>,
     foreign_items: Vec<ForeignItemId>,
     body_owners: Vec<LocalDefId>,
+    opaques: Vec<LocalDefId>,
 }
 
 impl<'tcx> ItemCollector<'tcx> {
@@ -1299,6 +1316,7 @@ impl<'tcx> ItemCollector<'tcx> {
             impl_items: Vec::default(),
             foreign_items: Vec::default(),
             body_owners: Vec::default(),
+            opaques: Vec::default(),
         }
     }
 }
@@ -1344,6 +1362,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
         intravisit::walk_inline_const(self, c)
     }
 
+    fn visit_opaque_ty(&mut self, o: &'hir OpaqueTy<'hir>) {
+        self.opaques.push(o.def_id);
+        intravisit::walk_opaque_ty(self, o)
+    }
+
     fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
         if let ExprKind::Closure(closure) = ex.kind {
             self.body_owners.push(closure.def_id);
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 7a07ef80ded..ad0d70152e1 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -28,6 +28,7 @@ pub struct ModuleItems {
     trait_items: Box<[TraitItemId]>,
     impl_items: Box<[ImplItemId]>,
     foreign_items: Box<[ForeignItemId]>,
+    opaques: Box<[LocalDefId]>,
     body_owners: Box<[LocalDefId]>,
 }
 
@@ -65,6 +66,10 @@ impl ModuleItems {
             .chain(self.foreign_items.iter().map(|id| id.owner_id))
     }
 
+    pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+        self.opaques.iter().copied()
+    }
+
     pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
         self.owners().map(|id| id.def_id)
     }
@@ -96,6 +101,13 @@ impl ModuleItems {
     ) -> Result<(), ErrorGuaranteed> {
         try_par_for_each_in(&self.foreign_items[..], |&id| f(id))
     }
+
+    pub fn par_opaques(
+        &self,
+        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
+    ) -> Result<(), ErrorGuaranteed> {
+        try_par_for_each_in(&self.opaques[..], |&id| f(id))
+    }
 }
 
 impl<'tcx> TyCtxt<'tcx> {
diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
index 32e2f3b4b16..13e35cd0909 100644
--- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
+++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
@@ -1,9 +1,9 @@
 //! Name resolution for lifetimes and late-bound type and const variables: type declarations.
 
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::ItemLocalId;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{ItemLocalId, OwnerId};
 use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable};
 
 use crate::ty;
@@ -47,11 +47,11 @@ pub enum ObjectLifetimeDefault {
 
 /// Maps the id of each lifetime reference to the lifetime decl
 /// that it corresponds to.
-#[derive(Default, HashStable, Debug)]
+#[derive(HashStable, Debug)]
 pub struct ResolveBoundVars {
     /// Maps from every use of a named (not anonymous) lifetime to a
     /// `Region` describing how that region is bound
-    pub defs: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, ResolvedArg>>,
+    pub defs: SortedMap<ItemLocalId, ResolvedArg>,
 
-    pub late_bound_vars: FxIndexMap<OwnerId, FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
+    pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 989fbd711c3..f0be70e00df 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -16,6 +16,7 @@ use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
@@ -1552,7 +1553,7 @@ rustc_queries! {
         feedable
     }
 
-    query check_well_formed(key: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
+    query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
         ensure_forwards_result_if_red
     }
@@ -1738,29 +1739,28 @@ rustc_queries! {
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes` for details.
-    query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars {
+    query resolve_bound_vars(owner_id: hir::OwnerId) -> &'tcx ResolveBoundVars {
         arena_cache
-        desc { "resolving lifetimes" }
+        desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(owner_id) }
     }
-    query named_variable_map(_: hir::OwnerId) ->
-        Option<&'tcx FxIndexMap<ItemLocalId, ResolvedArg>> {
-        desc { "looking up a named region" }
+    query named_variable_map(owner_id: hir::OwnerId) -> &'tcx SortedMap<ItemLocalId, ResolvedArg> {
+        desc { |tcx| "looking up a named region inside `{}`", tcx.def_path_str(owner_id) }
     }
-    query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {
-        desc { "testing if a region is late bound" }
+    query is_late_bound_map(owner_id: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {
+        desc { |tcx| "testing if a region is late bound inside `{}`", tcx.def_path_str(owner_id) }
     }
     /// For a given item's generic parameter, gets the default lifetimes to be used
     /// for each parameter if a trait object were to be passed for that parameter.
     /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`.
     /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`.
     /// This query will panic if passed something that is not a type parameter.
-    query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault {
-        desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) }
+    query object_lifetime_default(def_id: DefId) -> ObjectLifetimeDefault {
+        desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
-    query late_bound_vars_map(_: hir::OwnerId)
-        -> Option<&'tcx FxIndexMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
-        desc { "looking up late bound vars" }
+    query late_bound_vars_map(owner_id: hir::OwnerId)
+        -> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> {
+        desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) }
     }
 
     /// Computes the visibility of the provided `def_id`.
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 41a20e89cbf..71833eea5c0 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -25,10 +25,10 @@ pub enum PointerCoercion {
     ArrayToPointer,
 
     /// Unsize a pointer/reference value, e.g., `&[T; n]` to
-    /// `&[T]`. Note that the source could be a thin or fat pointer.
-    /// This will do things like convert thin pointers to fat
+    /// `&[T]`. Note that the source could be a thin or wide pointer.
+    /// This will do things like convert thin pointers to wide
     /// pointers, or convert structs containing thin pointers to
-    /// structs containing fat pointers, or convert between fat
+    /// structs containing wide pointers, or convert between wide
     /// pointers. We don't store the details of how the transform is
     /// done (in fact, we don't know that, because it might depend on
     /// the precise type parameters). We just store the target
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 2ffb273cb6f..27c1b88f93f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -56,7 +56,7 @@ use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
 use rustc_type_ir::solve::SolverMode;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
-use tracing::{debug, instrument};
+use tracing::{debug, trace};
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
@@ -2073,9 +2073,11 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// Returns the origin of the opaque type `def_id`.
-    #[instrument(skip(self), level = "trace", ret)]
+    #[track_caller]
     pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin {
-        self.hir().expect_item(def_id).expect_opaque_ty().origin
+        let origin = self.hir().expect_opaque_ty(def_id).origin;
+        trace!("opaque_type_origin({def_id:?}) => {origin:?}");
+        origin
     }
 }
 
@@ -2994,7 +2996,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn named_bound_var(self, id: HirId) -> Option<resolve_bound_vars::ResolvedArg> {
         debug!(?id, "named_region");
-        self.named_variable_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
+        self.named_variable_map(id.owner).get(&id.local_id).cloned()
     }
 
     pub fn is_late_bound(self, id: HirId) -> bool {
@@ -3003,12 +3005,9 @@ 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)
-                .and_then(|map| map.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().node_to_string(id))
+            }),
         )
     }
 
@@ -3031,8 +3030,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         loop {
             let parent = self.local_parent(opaque_lifetime_param_def_id);
-            let hir::OpaqueTy { lifetime_mapping, .. } =
-                self.hir_node_by_def_id(parent).expect_item().expect_opaque_ty();
+            let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent);
 
             let Some((lifetime, _)) = lifetime_mapping
                 .iter()
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 992eb264163..751f0c71eb4 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -507,14 +507,8 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
                     ..
                 },
                 _,
-            ) => {
-                self.0.push(ty);
-            }
-            hir::TyKind::OpaqueDef(item_id, _, _) => {
-                self.0.push(ty);
-                let item = self.1.item(item_id);
-                hir::intravisit::walk_item(self, item);
-            }
+            )
+            | hir::TyKind::OpaqueDef(..) => self.0.push(ty),
             _ => {}
         }
         hir::intravisit::walk_ty(self, ty);
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index cf0c29e0c8c..4ba2a9b1d73 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -164,17 +164,17 @@ impl Primitive {
     }
 }
 
-/// The first half of a fat pointer.
+/// The first half of a wide pointer.
 ///
 /// - For a trait object, this is the address of the box.
 /// - For a slice, this is the base address.
-pub const FAT_PTR_ADDR: usize = 0;
+pub const WIDE_PTR_ADDR: usize = 0;
 
-/// The second half of a fat pointer.
+/// The second half of a wide pointer.
 ///
 /// - For a trait object, this is the address of the vtable.
 /// - For a slice, this is the length.
-pub const FAT_PTR_EXTRA: usize = 1;
+pub const WIDE_PTR_EXTRA: usize = 1;
 
 /// The maximum supported number of lanes in a SIMD vector.
 ///
@@ -312,7 +312,7 @@ pub enum SizeSkeleton<'tcx> {
     /// that another SizeSkeleton is of equal size.
     Generic(ty::Const<'tcx>),
 
-    /// A potentially-fat pointer.
+    /// A potentially-wide pointer.
     Pointer {
         /// If true, this pointer is never null.
         non_zero: bool,
@@ -785,11 +785,11 @@ where
                     bug!("TyAndLayout::field({:?}): not applicable", this)
                 }
 
-                // Potentially-fat pointers.
+                // Potentially-wide pointers.
                 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                     assert!(i < this.fields.count());
 
-                    // Reuse the fat `*T` type as its own thin pointer data field.
+                    // Reuse the wide `*T` type as its own thin pointer data field.
                     // This provides information about, e.g., DST struct pointees
                     // (which may have no non-DST form), and will work as long
                     // as the `Abi` or `FieldsShape` is checked by users.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c4a28845085..f32daee7c44 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -187,8 +187,8 @@ pub struct ResolverGlobalCtxt {
     /// Mapping from ident span to path span for paths that don't exist as written, but that
     /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
     pub confused_type_with_std_module: FxIndexMap<Span, Span>,
-    pub doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
-    pub doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
+    pub doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
+    pub doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
     pub all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
     pub stripped_cfg_items: Steal<Vec<StrippedCfgItem>>,
 }
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index fd4e8f1cd4e..d20cb368278 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -179,6 +179,10 @@ pub struct Clause<'tcx>(
 );
 
 impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {
+    fn as_predicate(self) -> Predicate<'tcx> {
+        self.as_predicate()
+    }
+
     fn instantiate_supertrait(self, tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> Self {
         self.instantiate_supertrait(tcx, trait_ref)
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index db9978a7f53..3f00458d195 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -21,6 +21,7 @@ use rustc_target::spec::abi;
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::visit::TypeVisitableExt;
 use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
+use tracing::instrument;
 use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
 
 use super::GenericParamDefKind;
@@ -500,6 +501,7 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    #[instrument(level = "debug", skip(tcx))]
     pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
         Ty::new_alias(tcx, ty::Opaque, AliasTy::new_from_args(tcx, def_id, args))
     }
@@ -584,6 +586,16 @@ impl<'tcx> Ty<'tcx> {
         Ty::new_ref(tcx, r, ty, hir::Mutability::Not)
     }
 
+    pub fn new_pinned_ref(
+        tcx: TyCtxt<'tcx>,
+        r: Region<'tcx>,
+        ty: Ty<'tcx>,
+        mutbl: ty::Mutability,
+    ) -> Ty<'tcx> {
+        let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
+        Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()]))
+    }
+
     #[inline]
     pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> {
         Ty::new(tcx, ty::RawPtr(ty, mutbl))
@@ -1589,7 +1601,7 @@ impl<'tcx> Ty<'tcx> {
             .map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap())
     }
 
-    /// Returns the type of metadata for (potentially fat) pointers to this type,
+    /// Returns the type of metadata for (potentially wide) pointers to this type,
     /// or the struct tail if the metadata type cannot be determined.
     pub fn ptr_metadata_ty_or_tail(
         self,
@@ -1648,7 +1660,7 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    /// Returns the type of metadata for (potentially fat) pointers to this type.
+    /// Returns the type of metadata for (potentially wide) pointers to this type.
     /// Causes an ICE if the metadata type cannot be determined.
     pub fn ptr_metadata_ty(
         self,
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index f2541c37167..a3b117a3f19 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -225,7 +225,7 @@ where
     // FIXME: I think we should just control the flags externally,
     // and then we do not need this machinery.
     #[instrument(level = "debug")]
-    pub fn elaborate_drop(&mut self, bb: BasicBlock) {
+    fn elaborate_drop(&mut self, bb: BasicBlock) {
         match self.elaborator.drop_style(self.path, DropFlagMode::Deep) {
             DropStyle::Dead => {
                 self.elaborator
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index e65a5fdd5e7..df151f8cca3 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -63,7 +63,8 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             Some([item]) if item.has_name(sym::on) => return true,
             Some(_) | None => {
                 // Other possibilities should have been rejected by `rustc_parse::validate_attr`.
-                tcx.dcx().span_bug(attr.span, "unexpected value of coverage attribute");
+                // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880).
+                tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute");
             }
         }
     }
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 50c9702cb9b..0bb46675e9a 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1137,7 +1137,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
                 return Some(fields[1]);
             }
-            // We have an unsizing cast, which assigns the length to fat pointer metadata.
+            // We have an unsizing cast, which assigns the length to wide pointer metadata.
             (
                 UnOp::PtrMetadata,
                 Value::Cast {
@@ -1421,7 +1421,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         let mut inner = self.simplify_place_value(place, location)?;
 
-        // The length information is stored in the fat pointer.
+        // The length information is stored in the wide pointer.
         // Reborrowing copies length information from one pointer to the other.
         while let Value::Address { place: borrowed, .. } = self.get(inner)
             && let [PlaceElem::Deref] = borrowed.projection[..]
@@ -1430,7 +1430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             inner = borrowed;
         }
 
-        // We have an unsizing cast, which assigns the length to fat pointer metadata.
+        // We have an unsizing cast, which assigns the length to wide pointer metadata.
         if let Value::Cast { kind, from, to, .. } = self.get(inner)
             && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
             && let Some(from) = from.builtin_deref(true)
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 1844b97887a..9b9b0b705bf 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -494,8 +494,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
             }
             // Transfer the conditions on the copy rhs, after inversing polarity.
             Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => {
+                if !place.ty(self.body, self.tcx).ty.is_bool() {
+                    // Constructing the conditions by inverting the polarity
+                    // of equality is only correct for bools. That is to say,
+                    // `!a == b` is not `a != b` for integers greater than 1 bit.
+                    return;
+                }
                 let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return };
                 let Some(place) = self.map.find(place.as_ref()) else { return };
+                // FIXME: I think This could be generalized to not bool if we
+                // actually perform a logical not on the condition's value.
                 let conds = conditions.map(self.arena, Condition::inv);
                 state.insert_value_idx(place, conds, &self.map);
             }
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index ccc029b1e28..8f490094d60 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -600,13 +600,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             }
 
             Len(place) => {
-                let len = match self.get_const(place)? {
-                    Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
-                    Value::Aggregate { fields, .. } => fields.len() as u64,
-                    Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() {
-                        ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
-                        _ => return None,
-                    },
+                let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind()
+                {
+                    n.try_eval_target_usize(self.tcx, self.param_env)?
+                } else {
+                    match self.get_const(place)? {
+                        Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
+                        Value::Aggregate { fields, .. } => fields.len() as u64,
+                        Value::Uninit => return None,
+                    }
                 };
                 ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into()
             }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 05b3859e554..b4d084d4dff 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -119,7 +119,7 @@
 //!
 //! #### Unsizing Casts
 //! A subtle way of introducing use edges is by casting to a trait object.
-//! Since the resulting fat-pointer contains a reference to a vtable, we need to
+//! Since the resulting wide-pointer contains a reference to a vtable, we need to
 //! instantiate all dyn-compatible methods of the trait, as we need to store
 //! pointers to these functions even if they never get called anywhere. This can
 //! be seen as a special case of taking a function reference.
@@ -661,7 +661,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         let span = self.body.source_info(location).span;
 
         match *rvalue {
-            // When doing an cast from a regular pointer to a fat pointer, we
+            // When doing an cast from a regular pointer to a wide pointer, we
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(
@@ -985,7 +985,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
 /// ```
 ///
 /// Then the output of this function would be (SomeStruct, SomeTrait) since for
-/// constructing the `target` fat-pointer we need the vtable for that pair.
+/// constructing the `target` wide-pointer we need the vtable for that pair.
 ///
 /// Things can get more complicated though because there's also the case where
 /// the unsized type occurs as a field:
@@ -999,7 +999,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
 /// ```
 ///
 /// In this case, if `T` is sized, `&ComplexStruct<T>` is a thin pointer. If `T`
-/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is
+/// is unsized, `&SomeStruct` is a wide pointer, and the vtable it points to is
 /// for the pair of `T` (which is a trait) and the concrete type that `T` was
 /// originally coerced from:
 ///
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index f7a8b8780ed..da02f98d0e5 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -18,7 +18,7 @@ use std::path::Path;
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{AttrItem, Attribute, MetaItem, token};
+use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diag, FatalError, PResult};
@@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
 pub fn parse_cfg_attr(
     cfg_attr: &Attribute,
     psess: &ParseSess,
-) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
+) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
     const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
     const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
         <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index c65cf3f40f6..4aa56cb7624 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
-    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
-        let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
+    pub fn parse_cfg_attr(
+        &mut self,
+    ) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
+        let cfg_predicate = self.parse_meta_item_inner()?;
         self.expect(&token::Comma)?;
 
         // Presumably, the majority of the time there will only be one attr.
@@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
     /// ```ebnf
     /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
     /// ```
-    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
+    pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
         match self.parse_unsuffixed_meta_item_lit() {
             Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
             Err(err) => err.cancel(), // we provide a better error below
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index a24259a1e35..b3334bb70aa 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -814,7 +814,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::Mod
             | Target::GlobalAsm
             | Target::TyAlias
-            | Target::OpaqueTy
             | Target::Enum
             | Target::Variant
             | Target::Struct
@@ -1328,7 +1327,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         ) {
             let article = match target {
                 Target::ExternCrate
-                | Target::OpaqueTy
                 | Target::Enum
                 | Target::Impl
                 | Target::Expression
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index aa329fc546e..af17fbf7e4d 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -41,6 +41,7 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             | Node::TraitItem(..)
             | Node::Variant(..)
             | Node::AnonConst(..)
+            | Node::OpaqueTy(..)
     )
 }
 
@@ -494,6 +495,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             Node::ForeignItem(foreign_item) => {
                 intravisit::walk_foreign_item(self, foreign_item);
             }
+            Node::OpaqueTy(opaq) => intravisit::walk_opaque_ty(self, opaq),
             _ => {}
         }
         self.repr_has_repr_simd = had_repr_simd;
@@ -655,14 +657,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
         intravisit::walk_path(self, path);
     }
 
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-        if let TyKind::OpaqueDef(item_id, _, _) = ty.kind {
-            let item = self.tcx.hir().item(item_id);
-            intravisit::walk_item(self, item);
-        }
-        intravisit::walk_ty(self, ty);
-    }
-
     fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
         // When inline const blocks are used in pattern position, paths
         // referenced by it should be considered as used.
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 903fb114744..8ad14b6eb74 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -230,7 +230,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             ForeignMod,
             GlobalAsm,
             TyAlias,
-            OpaqueTy,
             Enum,
             Struct,
             Union,
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 925ee262022..056318fbcb7 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -236,7 +236,6 @@ impl<'tcx> ReachableContext<'tcx> {
                     // worklist, as determined by the privacy pass
                     hir::ItemKind::ExternCrate(_)
                     | hir::ItemKind::Use(..)
-                    | hir::ItemKind::OpaqueTy(..)
                     | hir::ItemKind::TyAlias(..)
                     | hir::ItemKind::Macro(..)
                     | hir::ItemKind::Mod(..)
@@ -287,7 +286,8 @@ impl<'tcx> ReachableContext<'tcx> {
             | Node::Field(_)
             | Node::Ty(_)
             | Node::Crate(_)
-            | Node::Synthetic => {}
+            | Node::Synthetic
+            | Node::OpaqueTy(..) => {}
             _ => {
                 bug!(
                     "found unexpected node kind in worklist: {} ({:?})",
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9094b00fbfb..f67c4cb922c 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -402,8 +402,6 @@ struct EmbargoVisitor<'tcx> {
     ///     n::p::f()
     /// }
     macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
-    /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable.
-    impl_trait_pass: bool,
     /// Has something changed in the level map?
     changed: bool,
 }
@@ -635,21 +633,6 @@ impl<'tcx> EmbargoVisitor<'tcx> {
 
 impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        if self.impl_trait_pass
-            && let hir::ItemKind::OpaqueTy(opaque) = item.kind
-            && !opaque.in_trait
-        {
-            // FIXME: This is some serious pessimization intended to workaround deficiencies
-            // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
-            // reachable if they are returned via `impl Trait`, even from private functions.
-            let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
-            self.reach_through_impl_trait(item.owner_id.def_id, pub_ev)
-                .generics()
-                .predicates()
-                .ty();
-            return;
-        }
-
         // Update levels of nested things and mark all items
         // in interfaces of reachable items as reachable.
         let item_ev = self.get(item.owner_id.def_id);
@@ -659,7 +642,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::GlobalAsm(..) => {}
             // The interface is empty, and all nested items are processed by `visit_item`.
-            hir::ItemKind::Mod(..) | hir::ItemKind::OpaqueTy(..) => {}
+            hir::ItemKind::Mod(..) => {}
             hir::ItemKind::Macro(macro_def, _) => {
                 if let Some(item_ev) = item_ev {
                     self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
@@ -1725,19 +1708,59 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
         tcx,
         effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
         macro_reachable: Default::default(),
-        // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and
-        // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't
-        // care about link-time reachability, keep them unreachable (issue #75100).
-        impl_trait_pass: !tcx.sess.opts.actually_rustdoc,
         changed: false,
     };
 
     visitor.effective_visibilities.check_invariants(tcx);
-    if visitor.impl_trait_pass {
+
+    // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and
+    // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't
+    // care about link-time reachability, keep them unreachable (issue #75100).
+    let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
+    if impl_trait_pass {
         // Underlying types of `impl Trait`s are marked as reachable unconditionally,
         // so this pass doesn't need to be a part of the fixed point iteration below.
-        tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
-        visitor.impl_trait_pass = false;
+        let krate = tcx.hir_crate_items(());
+        for id in krate.opaques() {
+            let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
+            let should_visit = match opaque.origin {
+                hir::OpaqueTyOrigin::FnReturn {
+                    parent,
+                    in_trait_or_impl: Some(hir::RpitContext::Trait),
+                }
+                | hir::OpaqueTyOrigin::AsyncFn {
+                    parent,
+                    in_trait_or_impl: Some(hir::RpitContext::Trait),
+                } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
+                    hir::TraitFn::Required(_) => false,
+                    hir::TraitFn::Provided(..) => true,
+                },
+
+                // Always visit RPITs in functions that have definitions,
+                // and all TAITs.
+                hir::OpaqueTyOrigin::FnReturn {
+                    in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                    ..
+                }
+                | hir::OpaqueTyOrigin::AsyncFn {
+                    in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
+                    ..
+                }
+                | hir::OpaqueTyOrigin::TyAlias { .. } => true,
+            };
+            if should_visit {
+                // FIXME: This is some serious pessimization intended to workaround deficiencies
+                // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
+                // reachable if they are returned via `impl Trait`, even from private functions.
+                let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
+                visitor
+                    .reach_through_impl_trait(opaque.def_id, pub_ev)
+                    .generics()
+                    .predicates()
+                    .ty();
+            }
+        }
+
         visitor.changed = false;
     }
 
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 69742bb49b1..df898e0587f 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -2,7 +2,7 @@
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
-#![allow(rustc::potential_query_instability, unused_parens)]
+#![allow(unused_parens)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 0c1a0038f9c..24a0c252e55 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1196,8 +1196,8 @@ pub struct Resolver<'ra, 'tcx> {
     stripped_cfg_items: Vec<StrippedCfgItem<NodeId>>,
 
     effective_visibilities: EffectiveVisibilities,
-    doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
-    doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
+    doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
+    doc_link_traits_in_scope: FxIndexMap<LocalDefId, Vec<DefId>>,
     all_macro_rules: FxHashMap<Symbol, Res>,
 
     /// Invocation ids of all glob delegations.
@@ -2148,7 +2148,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
-            PathResult::NonModule(path_res) => path_res.full_res(),
+            PathResult::NonModule(path_res) => {
+                path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _)))
+            }
             PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
                 None
             }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 320d6616384..53834198f63 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -315,7 +315,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>,
 /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
 /// Rust types that are not used at the FFI boundary.
 #[instrument(level = "trace", skip(tcx, dict))]
-pub fn encode_ty<'tcx>(
+pub(crate) fn encode_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     dict: &mut FxHashMap<DictKey<'tcx>, usize>,
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 5f7184a4240..83dcceeaa84 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -291,7 +291,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
 ///   the Fn trait that defines the method (for being attached as a secondary type id).
 ///
 #[instrument(level = "trace", skip(tcx))]
-pub fn transform_instance<'tcx>(
+pub(crate) fn transform_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     mut instance: Instance<'tcx>,
     options: TransformTyOptions,
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index 66ad70d8d18..b936a299b09 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -72,7 +72,7 @@ pub struct NativeLib {
     pub name: Symbol,
     /// If packed_bundled_libs enabled, actual filename of library is stored.
     pub filename: Option<Symbol>,
-    pub cfg: Option<ast::MetaItem>,
+    pub cfg: Option<ast::NestedMetaItem>,
     pub foreign_module: Option<DefId>,
     pub verbatim: Option<bool>,
     pub dll_imports: Vec<DllImport>,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e8aa129c6cd..1527600e764 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -544,6 +544,7 @@ symbols! {
         cfg_accessible,
         cfg_attr,
         cfg_attr_multi,
+        cfg_boolean_literals,
         cfg_doctest,
         cfg_eval,
         cfg_fmt_debug,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index f4469467249..352861c5ccb 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -637,7 +637,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
         }
     }
 
-    /// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead.
+    /// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead.
     /// This is valid for both sized and unsized arguments.
     pub fn make_indirect(&mut self) {
         match self.mode {
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 3eaff652618..fc92e755fea 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -135,7 +135,7 @@ impl<'a> Layout<'a> {
 /// Note that the layout is NOT guaranteed to always be identical
 /// to that obtained from `layout_of(ty)`, as we need to produce
 /// layouts for which Rust types do not exist, such as enum variants
-/// or synthetic fields of enums (i.e., discriminants) and fat pointers.
+/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct TyAndLayout<'a, Ty> {
     pub ty: Ty,
diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr_gnu.rs
index fb97738618b..4f348af21ad 100644
--- a/compiler/rustc_target/src/spec/base/avr_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/avr_gnu.rs
@@ -19,6 +19,8 @@ pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
         llvm_target: "avr-unknown-unknown".into(),
         pointer_width: 16,
         options: TargetOptions {
+            env: "gnu".into(),
+
             c_int_width: "16".into(),
             cpu: target_cpu.into(),
             exe_suffix: ".elf".into(),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index c557091242e..18ec8ee9476 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1830,6 +1830,7 @@ supported_targets! {
 
     ("armv7-unknown-trusty", armv7_unknown_trusty),
     ("aarch64-unknown-trusty", aarch64_unknown_trusty),
+    ("x86_64-unknown-trusty", x86_64_unknown_trusty),
 
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
     ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf),
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
index 7e14c5efe71..e5ae1064d97 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabi.rs
@@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
         arch: "arm".into(),
         options: TargetOptions {
+            abi: "eabi".into(),
             linker: Some("arm-kmc-eabi-gcc".into()),
             features: "+v7,+soft-float,+thumb2,-neon".into(),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
index 1958f4a7c30..0879fa24a1b 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs
@@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
         arch: "arm".into(),
         options: TargetOptions {
+            abi: "eabihf".into(),
             linker: Some("arm-kmc-eabi-gcc".into()),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
index 0cd4faefd6b..0157d03f854 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_none_elf.rs
@@ -7,7 +7,6 @@ pub(crate) fn target() -> Target {
         linker: Some("sparc-elf-gcc".into()),
         endian: Endian::Big,
         cpu: "v7".into(),
-        abi: "elf".into(),
         max_atomic_width: Some(32),
         atomic_cas: true,
         panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
new file mode 100644
index 00000000000..a6af06b03db
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs
@@ -0,0 +1,38 @@
+// Trusty OS target for X86_64.
+
+use crate::spec::{
+    LinkSelfContainedDefault, PanicStrategy, RelroLevel, StackProbeType, Target, TargetOptions,
+};
+
+pub(crate) fn target() -> Target {
+    Target {
+        llvm_target: "x86_64-unknown-unknown-musl".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("x86_64 Trusty".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 64,
+        data_layout:
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+        arch: "x86_64".into(),
+        options: TargetOptions {
+            executables: true,
+            max_atomic_width: Some(64),
+            panic_strategy: PanicStrategy::Abort,
+            os: "trusty".into(),
+            link_self_contained: LinkSelfContainedDefault::InferredForMusl,
+            position_independent_executables: true,
+            static_position_independent_executables: true,
+            crt_static_default: true,
+            crt_static_respected: true,
+            dynamic_linking: false,
+            plt_by_default: false,
+            relro_level: RelroLevel::Full,
+            stack_probes: StackProbeType::Inline,
+            mcount: "\u{1}_mcount".into(),
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 4bde120cba9..a6ecd1cc987 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -284,14 +284,9 @@ pub fn suggest_new_region_bound(
         }
         match fn_return.kind {
             // FIXME(precise_captures): Suggest adding to `use<...>` list instead.
-            TyKind::OpaqueDef(item_id, _, _) => {
-                let item = tcx.hir().item(item_id);
-                let ItemKind::OpaqueTy(opaque) = &item.kind else {
-                    return;
-                };
-
+            TyKind::OpaqueDef(opaque, _) => {
                 // Get the identity type for this RPIT
-                let did = item_id.owner_id.to_def_id();
+                let did = opaque.def_id.to_def_id();
                 let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did));
 
                 if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
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 7802d5bf7a6..cf0ab630f2e 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
@@ -720,7 +720,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_item(opaque_local_def_id).expect_opaque_ty()
+                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 41fe8a2bf22..94610a9e0e6 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -842,14 +842,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         lifetime: Region<'tcx>,
         add_lt_suggs: &mut Vec<(Span, String)>,
     ) -> String {
-        struct LifetimeReplaceVisitor<'a, 'tcx> {
-            tcx: TyCtxt<'tcx>,
+        struct LifetimeReplaceVisitor<'a> {
             needle: hir::LifetimeName,
             new_lt: &'a str,
             add_lt_suggs: &'a mut Vec<(Span, String)>,
         }
 
-        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_, 'tcx> {
+        impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> {
             fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
                 if lt.res == self.needle {
                     self.add_lt_suggs.push(lt.suggestion(self.new_lt));
@@ -857,10 +856,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
 
             fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
-                let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind else {
+                let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else {
                     return hir::intravisit::walk_ty(self, ty);
                 };
-                let opaque_ty = self.tcx.hir().item(item_id).expect_opaque_ty();
                 if let Some(&(_, b)) =
                     opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
                 {
@@ -905,7 +903,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         };
 
         let mut visitor = LifetimeReplaceVisitor {
-            tcx: self.tcx,
             needle: hir::LifetimeName::Param(lifetime_def_id),
             add_lt_suggs,
             new_lt: &new_lt,
@@ -1269,9 +1266,9 @@ fn suggest_precise_capturing<'tcx>(
     diag: &mut Diag<'_>,
 ) {
     let hir::OpaqueTy { bounds, origin, .. } =
-        tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+        tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
 
-    let hir::OpaqueTyOrigin::FnReturn(fn_def_id) = *origin else {
+    let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } = *origin else {
         return;
     };
 
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 6c3f3afce11..709b6eb18e3 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -731,12 +731,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let exp_local_id = exp_def_id.as_local()?;
 
                 match (
-                    &self.tcx.hir().expect_item(last_local_id).kind,
-                    &self.tcx.hir().expect_item(exp_local_id).kind,
+                    &self.tcx.hir().expect_opaque_ty(last_local_id),
+                    &self.tcx.hir().expect_opaque_ty(exp_local_id),
                 ) {
                     (
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
-                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
+                        hir::OpaqueTy { bounds: last_bounds, .. },
+                        hir::OpaqueTy { bounds: exp_bounds, .. },
                     ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match (
                         left, right,
                     ) {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 5af117a3f48..824c25db07d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1,6 +1,7 @@
 use core::ops::ControlFlow;
 use std::borrow::Cow;
 
+use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
@@ -245,6 +246,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                         span, "silent safe transmute error"
                                     );
                                 }
+                                GetSafeTransmuteErrorAndReason::Default => {
+                                    (err_msg, None)
+                                }
                                 GetSafeTransmuteErrorAndReason::Error {
                                     err_msg,
                                     safe_transmute_explanation,
@@ -570,7 +574,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                     ty::PredicateKind::DynCompatible(trait_def_id) => {
                         let violations = self.tcx.dyn_compatibility_violations(trait_def_id);
-                        report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations)
+                        let mut err = report_dyn_incompatibility(
+                            self.tcx,
+                            span,
+                            None,
+                            trait_def_id,
+                            violations,
+                        );
+                        if let hir::Node::Item(item) =
+                            self.tcx.hir_node_by_def_id(obligation.cause.body_id)
+                            && let hir::ItemKind::Impl(impl_) = item.kind
+                            && let None = impl_.of_trait
+                            && let hir::TyKind::TraitObject(_, _, syntax) = impl_.self_ty.kind
+                            && let TraitObjectSyntax::None = syntax
+                            && impl_.self_ty.span.edition().at_least_rust_2021()
+                        {
+                            // Silence the dyn-compatibility error in favor of the missing dyn on
+                            // self type error. #131051.
+                            err.downgrade_to_delayed_bug();
+                        }
+                        err
                     }
 
                     ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
@@ -2226,6 +2249,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> GetSafeTransmuteErrorAndReason {
         use rustc_transmute::Answer;
 
+        // We don't assemble a transmutability candidate for types that are generic
+        // and we should have ambiguity for types that still have non-region infer.
+        if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() {
+            return GetSafeTransmuteErrorAndReason::Default;
+        }
+
         // Erase regions because layout code doesn't particularly care about regions.
         let trait_ref =
             self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
@@ -2248,6 +2277,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let dst = trait_ref.args.type_at(0);
         let src = trait_ref.args.type_at(1);
+
         let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
 
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2630,7 +2660,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         def_id: DefId,
     ) -> ErrorGuaranteed {
         let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
-            hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
+            hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => {
                 "opaque type".to_string()
             }
             hir::OpaqueTyOrigin::TyAlias { .. } => {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 109bae10b54..becc1acfb66 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -43,6 +43,7 @@ pub struct ImplCandidate<'tcx> {
 
 enum GetSafeTransmuteErrorAndReason {
     Silent,
+    Default,
     Error { err_msg: String, safe_transmute_explanation: Option<String> },
 }
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 2c7ca50f954..e9a2c5b8d8e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -1,7 +1,7 @@
 use std::iter;
 use std::path::PathBuf;
 
-use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
+use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
@@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
 
 #[derive(Debug)]
 pub struct OnUnimplementedDirective {
-    pub condition: Option<MetaItem>,
+    pub condition: Option<NestedMetaItem>,
     pub subcommands: Vec<OnUnimplementedDirective>,
     pub message: Option<OnUnimplementedFormatString>,
     pub label: Option<OnUnimplementedFormatString>,
@@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective {
             let cond = item_iter
                 .next()
                 .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
-                .meta_item()
+                .meta_item_or_bool()
                 .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
             attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
                 if let Some(value) = cfg.value
@@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective {
                         IgnoredDiagnosticOption::maybe_emit_warning(
                             tcx,
                             item_def_id,
-                            directive.condition.as_ref().map(|i| i.span),
-                            aggr.condition.as_ref().map(|i| i.span),
+                            directive.condition.as_ref().map(|i| i.span()),
+                            aggr.condition.as_ref().map(|i| i.span()),
                             "condition",
                         );
                         IgnoredDiagnosticOption::maybe_emit_warning(
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 6df7fac949c..87834c329e1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -355,12 +355,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         | hir::ItemKind::Fn(_, generics, _)
                         | hir::ItemKind::TyAlias(_, generics)
                         | hir::ItemKind::Const(_, generics, _)
-                        | hir::ItemKind::TraitAlias(generics, _)
-                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                        | hir::ItemKind::TraitAlias(generics, _),
                     ..
                 })
                 | hir::Node::TraitItem(hir::TraitItem { generics, .. })
                 | hir::Node::ImplItem(hir::ImplItem { generics, .. })
+                | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. })
                     if param_ty =>
                 {
                     // We skip the 0'th arg (self) because we do not want
@@ -421,10 +421,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         | hir::ItemKind::Fn(_, generics, _)
                         | hir::ItemKind::TyAlias(_, generics)
                         | hir::ItemKind::Const(_, generics, _)
-                        | hir::ItemKind::TraitAlias(generics, _)
-                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                        | hir::ItemKind::TraitAlias(generics, _),
                     ..
-                }) if !param_ty => {
+                })
+                | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. })
+                    if !param_ty =>
+                {
                     // Missing generic type parameter bound.
                     if suggest_arbitrary_trait_bound(
                         self.tcx,
@@ -4542,7 +4544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // ... whose signature is `async` (i.e. this is an AFIT)
         let (sig, body) = item.expect_fn();
-        let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
+        let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(opaq_def, ..), .. }) =
             sig.decl.output
         else {
             // This should never happen, but let's not ICE.
@@ -4551,7 +4553,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         // Check that this is *not* a nested `impl Future` RPIT in an async fn
         // (i.e. `async fn foo() -> impl Future`)
-        if def.owner_id.to_def_id() != opaque_def_id {
+        if opaq_def.def_id.to_def_id() != opaque_def_id {
             return;
         }
 
@@ -5159,7 +5161,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
     };
     let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span);
 
-    let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+    let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
     let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else {
         // `async fn` should always lower to a single bound... but don't ICE.
         return None;
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index a17c007debd..11d72106b22 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -20,7 +20,6 @@
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
 #![feature(cfg_version)]
-#![feature(control_flow_enum)]
 #![feature(extract_if)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 6d5859a5a65..17eddbfcd7f 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -195,10 +195,11 @@ pub(crate) mod rustc {
     impl<'tcx> From<&LayoutError<'tcx>> for Err {
         fn from(err: &LayoutError<'tcx>) -> Self {
             match err {
-                LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout,
+                LayoutError::Unknown(..)
+                | LayoutError::ReferencesError(..)
+                | LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
                 LayoutError::SizeOverflow(..) => Self::SizeOverflow,
                 LayoutError::Cycle(err) => Self::TypeError(*err),
-                err => unimplemented!("{:?}", err),
             }
         }
     }
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 1e5da4ec49d..9dabcea706f 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -40,7 +40,7 @@ mod rustc {
         /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
         /// then computes an answer using those trees.
         #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
-        pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
+        pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
             let Self { src, dst, assume, context } = self;
 
             let layout_cx = LayoutCx::new(context, ParamEnv::reveal_all());
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index f23c2cf2c07..3d6c09bf89c 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -357,7 +357,7 @@ fn fn_abi_of_instance<'tcx>(
     )
 }
 
-// Handle safe Rust thin and fat pointers.
+// Handle safe Rust thin and wide pointers.
 fn adjust_for_rust_scalar<'tcx>(
     cx: LayoutCx<'tcx>,
     attrs: &mut ArgAttributes,
@@ -810,7 +810,7 @@ fn make_thin_self_ptr<'tcx>(
     layout: TyAndLayout<'tcx>,
 ) -> TyAndLayout<'tcx> {
     let tcx = cx.tcx();
-    let fat_pointer_ty = if layout.is_unsized() {
+    let wide_pointer_ty = if layout.is_unsized() {
         // unsized `self` is passed as a pointer to `self`
         // FIXME (mikeyhew) change this to use &own if it is ever added to the language
         Ty::new_mut_ptr(tcx, layout.ty)
@@ -825,15 +825,15 @@ fn make_thin_self_ptr<'tcx>(
         // elsewhere in the compiler as a method on a `dyn Trait`.
         // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
         // get a built-in pointer type
-        let mut fat_pointer_layout = layout;
-        while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() {
-            fat_pointer_layout = fat_pointer_layout
+        let mut wide_pointer_layout = layout;
+        while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() {
+            wide_pointer_layout = wide_pointer_layout
                 .non_1zst_field(cx)
                 .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type")
                 .1
         }
 
-        fat_pointer_layout.ty
+        wide_pointer_layout.ty
     };
 
     // we now have a type like `*mut RcBox<dyn Trait>`
@@ -842,7 +842,7 @@ fn make_thin_self_ptr<'tcx>(
     let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit);
 
     TyAndLayout {
-        ty: fat_pointer_ty,
+        ty: wide_pointer_ty,
 
         // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
         // should always work because the type is always `*mut ()`.
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 6726db8bb54..a057caa9329 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -316,19 +316,16 @@ fn associated_types_for_impl_traits_in_associated_fn(
 
     match tcx.def_kind(parent_def_id) {
         DefKind::Trait => {
-            struct RPITVisitor<'tcx> {
+            struct RPITVisitor {
                 rpits: FxIndexSet<LocalDefId>,
-                tcx: TyCtxt<'tcx>,
             }
 
-            impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
+            impl<'tcx> Visitor<'tcx> for RPITVisitor {
                 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-                    if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind
-                        && self.rpits.insert(item_id.owner_id.def_id)
+                    if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind
+                        && self.rpits.insert(opaq.def_id)
                     {
-                        let opaque_item =
-                            self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty();
-                        for bound in opaque_item.bounds {
+                        for bound in opaq.bounds {
                             intravisit::walk_param_bound(self, bound);
                         }
                     }
@@ -336,7 +333,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
                 }
             }
 
-            let mut visitor = RPITVisitor { tcx, rpits: FxIndexSet::default() };
+            let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
 
             if let Some(output) = tcx.hir().get_fn_output(fn_def_id) {
                 visitor.visit_fn_ret_ty(output);
@@ -379,7 +376,8 @@ fn associated_type_for_impl_trait_in_trait(
     tcx: TyCtxt<'_>,
     opaque_ty_def_id: LocalDefId,
 ) -> LocalDefId {
-    let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) =
+    let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
+    | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
         tcx.opaque_type_origin(opaque_ty_def_id)
     else {
         bug!("expected opaque for {opaque_ty_def_id:?}");
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index bac0d020d72..5e2232ff47d 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -132,6 +132,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         TaitInBodyFinder { collector: self }.visit_expr(body);
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
         if !self.seen.insert(alias_ty.def_id.expect_local()) {
             return;
@@ -141,7 +142,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
         trace!(?origin);
         match origin {
-            rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
+            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;
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 61736633cfa..dac45ff2aba 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -44,6 +44,46 @@ pub trait Elaboratable<I: Interner> {
     ) -> Self;
 }
 
+pub struct ClauseWithSupertraitSpan<I: Interner> {
+    pub pred: I::Predicate,
+    // Span of the original elaborated predicate.
+    pub original_span: I::Span,
+    // Span of the supertrait predicatae that lead to this clause.
+    pub supertrait_span: I::Span,
+}
+impl<I: Interner> ClauseWithSupertraitSpan<I> {
+    pub fn new(pred: I::Predicate, span: I::Span) -> Self {
+        ClauseWithSupertraitSpan { pred, original_span: span, supertrait_span: span }
+    }
+}
+impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
+    fn predicate(&self) -> <I as Interner>::Predicate {
+        self.pred
+    }
+
+    fn child(&self, clause: <I as Interner>::Clause) -> Self {
+        ClauseWithSupertraitSpan {
+            pred: clause.as_predicate(),
+            original_span: self.original_span,
+            supertrait_span: self.supertrait_span,
+        }
+    }
+
+    fn child_with_derived_cause(
+        &self,
+        clause: <I as Interner>::Clause,
+        supertrait_span: <I as Interner>::Span,
+        _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
+        _index: usize,
+    ) -> Self {
+        ClauseWithSupertraitSpan {
+            pred: clause.as_predicate(),
+            original_span: self.original_span,
+            supertrait_span: supertrait_span,
+        }
+    }
+}
+
 pub fn elaborate<I: Interner, O: Elaboratable<I>>(
     cx: I,
     obligations: impl IntoIterator<Item = O>,
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 59a83ea5412..69665df4bfc 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -460,6 +460,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
     + Elaboratable<I>
 {
+    fn as_predicate(self) -> I::Predicate;
+
     fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> {
         self.kind()
             .map_bound(|clause| if let ty::ClauseKind::Trait(t) = clause { Some(t) } else { None })
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index ab9fc218d19..9f4db7e4833 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -946,10 +946,10 @@ pub enum PointerCoercion {
     ArrayToPointer,
 
     /// Unsize a pointer/reference value, e.g., `&[T; n]` to
-    /// `&[T]`. Note that the source could be a thin or fat pointer.
-    /// This will do things like convert thin pointers to fat
+    /// `&[T]`. Note that the source could be a thin or wide pointer.
+    /// This will do things like convert thin pointers to wide
     /// pointers, or convert structs containing thin pointers to
-    /// structs containing fat pointers, or convert between fat
+    /// structs containing wide pointers, or convert between wide
     /// pointers.
     Unsize,
 }
diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs
index aeae866e9d3..e2d1ff7fdd3 100644
--- a/compiler/stable_mir/src/mir/visit.rs
+++ b/compiler/stable_mir/src/mir/visit.rs
@@ -76,9 +76,9 @@ pub trait MirVisitor {
         self.super_place(place, ptx, location)
     }
 
-    fn visit_projection_elem<'a>(
+    fn visit_projection_elem(
         &mut self,
-        place_ref: PlaceRef<'a>,
+        place_ref: PlaceRef<'_>,
         elem: &ProjectionElem,
         ptx: PlaceContext,
         location: Location,