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_lowering/src/lib.rs6
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs509
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs16
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/offset_of.rs99
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs50
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs6
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs2
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml8
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs17
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs8
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_graphviz/src/lib.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs61
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs3
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl4
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs200
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs58
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs10
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs3
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs7
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs8
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs4
-rw-r--r--compiler/rustc_lint/src/builtin.rs7
-rw-r--r--compiler/rustc_lint/src/types.rs4
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs3
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs9
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs33
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs9
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs22
-rw-r--r--compiler/rustc_middle/src/ty/error.rs4
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs14
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs17
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs8
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs5
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs51
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs3
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml2
-rw-r--r--compiler/rustc_mir_transform/messages.ftl66
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs65
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs23
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs68
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs18
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs76
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs245
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs16
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs33
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs38
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs12
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs6
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs (renamed from compiler/rustc_mir_transform/src/instcombine.rs)50
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs12
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs10
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs3
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs4
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs2
-rw-r--r--compiler/rustc_monomorphize/src/util.rs4
-rw-r--r--compiler/rustc_parse/messages.ftl4
-rw-r--r--compiler/rustc_parse/src/errors.rs15
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs61
-rw-r--r--compiler/rustc_parse/src/parser/item.rs33
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs6
-rw-r--r--compiler/rustc_privacy/src/lib.rs33
-rw-r--r--compiler/rustc_session/src/config.rs4
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs2
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs9
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs42
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/messages.ftl2
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs163
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs86
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs1
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs29
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs2
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs28
-rw-r--r--compiler/rustc_type_ir/src/lib.rs27
-rw-r--r--compiler/rustc_type_ir/src/sty.rs1
130 files changed, 1886 insertions, 993 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4100efb6eb3..0d21c8a84d0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1477,6 +1477,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// Given a function definition like:
     ///
     /// ```rust
+    /// use std::fmt::Debug;
+    ///
     /// fn test<'a, T: Debug>(x: &'a T) -> impl Debug + 'a {
     ///     x
     /// }
@@ -1484,13 +1486,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ///
     /// we will create a TAIT definition in the HIR like
     ///
-    /// ```
+    /// ```rust,ignore (pseudo-Rust)
     /// type TestReturn<'a, T, 'x> = impl Debug + 'x
     /// ```
     ///
     /// and return a type like `TestReturn<'static, T, 'a>`, so that the function looks like:
     ///
-    /// ```rust
+    /// ```rust,ignore (pseudo-Rust)
     /// fn test<'a, T: Debug>(x: &'a T) -> TestReturn<'static, T, 'a>
     /// ```
     ///
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index b960671bf6e..3d5056d82c5 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -603,6 +603,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(yeet_expr, "`do yeet` expression is experimental");
     gate_all!(dyn_star, "`dyn*` trait objects are experimental");
     gate_all!(const_closures, "const closures are experimental");
+    gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
 
     if !visitor.features.negative_bounds {
         for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index b74c59bca30..87c32ffce12 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -556,8 +556,7 @@ impl<'a> State<'a> {
                 self.pclose();
             }
             ast::ExprKind::OffsetOf(container, fields) => {
-                // FIXME: This should have its own syntax, distinct from a macro invocation.
-                self.word("offset_of!");
+                self.word("builtin # offset_of");
                 self.popen();
                 self.rbox(0, Inconsistent);
                 self.print_type(container);
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 7558247948f..6286033e067 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
@@ -478,179 +478,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 match self.local_names[local] {
                     Some(name) if !local_decl.from_compiler_desugaring() => {
-                        let label = match *local_decl.local_info() {
-                            LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
-                                let (span, suggestion) =
-                                    suggest_ampmut_self(self.infcx.tcx, local_decl);
-                                Some((true, span, suggestion))
-                            }
-
-                            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
-                                binding_mode: ty::BindingMode::BindByValue(_),
-                                opt_ty_info,
-                                ..
-                            })) => {
-                                // check if the RHS is from desugaring
-                                let opt_assignment_rhs_span =
-                                    self.body.find_assignments(local).first().map(|&location| {
-                                        if let Some(mir::Statement {
-                                            source_info: _,
-                                            kind:
-                                                mir::StatementKind::Assign(box (
-                                                    _,
-                                                    mir::Rvalue::Use(mir::Operand::Copy(place)),
-                                                )),
-                                        }) = self.body[location.block]
-                                            .statements
-                                            .get(location.statement_index)
-                                        {
-                                            self.body.local_decls[place.local].source_info.span
-                                        } else {
-                                            self.body.source_info(location).span
-                                        }
-                                    });
-                                match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
-                                    // on for loops, RHS points to the iterator part
-                                    Some(DesugaringKind::ForLoop) => {
-                                        self.suggest_similar_mut_method_for_for_loop(&mut err);
-                                        err.span_label(opt_assignment_rhs_span.unwrap(), format!(
-                                            "this iterator yields `{pointer_sigil}` {pointer_desc}s",
-                                        ));
-                                        None
-                                    }
-                                    // don't create labels for compiler-generated spans
-                                    Some(_) => None,
-                                    None => {
-                                        let label = if name != kw::SelfLower {
-                                            suggest_ampmut(
-                                                self.infcx.tcx,
-                                                local_decl,
-                                                opt_assignment_rhs_span,
-                                                opt_ty_info,
-                                            )
-                                        } else {
-                                            match local_decl.local_info() {
-                                                LocalInfo::User(mir::BindingForm::Var(
-                                                    mir::VarBindingForm {
-                                                        opt_ty_info: None, ..
-                                                    },
-                                                )) => {
-                                                    let (span, sugg) = suggest_ampmut_self(
-                                                        self.infcx.tcx,
-                                                        local_decl,
-                                                    );
-                                                    (true, span, sugg)
-                                                }
-                                                // explicit self (eg `self: &'a Self`)
-                                                _ => suggest_ampmut(
-                                                    self.infcx.tcx,
-                                                    local_decl,
-                                                    opt_assignment_rhs_span,
-                                                    opt_ty_info,
-                                                ),
-                                            }
-                                        };
-                                        Some(label)
-                                    }
-                                }
-                            }
-
-                            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
-                                binding_mode: ty::BindingMode::BindByReference(_),
-                                ..
-                            })) => {
-                                let pattern_span = local_decl.source_info.span;
-                                suggest_ref_mut(self.infcx.tcx, pattern_span)
-                                    .map(|replacement| (true, pattern_span, replacement))
-                            }
-
-                            _ => unreachable!(),
-                        };
-
-                        match label {
-                            Some((true, err_help_span, suggested_code)) => {
-                                let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
-                                if !is_trait_sig {
-                                    err.span_suggestion_verbose(
-                                        err_help_span,
-                                        format!(
-                                            "consider changing this to be a mutable {pointer_desc}"
-                                        ),
-                                        suggested_code,
-                                        Applicability::MachineApplicable,
-                                    );
-                                } else if let Some(x) = local_trait {
-                                    err.span_suggestion_verbose(
-                                        x,
-                                        format!(
-                                            "consider changing that to be a mutable {pointer_desc}"
-                                        ),
-                                        suggested_code,
-                                        Applicability::MachineApplicable,
-                                    );
-                                }
-                            }
-                            Some((false, err_label_span, message)) => {
-                                struct BindingFinder {
-                                    span: Span,
-                                    hir_id: Option<hir::HirId>,
-                                }
-
-                                impl<'tcx> Visitor<'tcx> for BindingFinder {
-                                    fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
-                                        if let hir::StmtKind::Local(local) = s.kind {
-                                            if local.pat.span == self.span {
-                                                self.hir_id = Some(local.hir_id);
-                                            }
-                                        }
-                                        hir::intravisit::walk_stmt(self, s);
-                                    }
-                                }
-                                let hir_map = self.infcx.tcx.hir();
-                                let def_id = self.body.source.def_id();
-                                let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
-                                let node = hir_map.find(hir_id);
-                                let hir_id = if let Some(hir::Node::Item(item)) = node
-                                    && let hir::ItemKind::Fn(.., body_id) = item.kind
-                                {
-                                    let body = hir_map.body(body_id);
-                                    let mut v = BindingFinder {
-                                        span: err_label_span,
-                                        hir_id: None,
-                                    };
-                                    v.visit_body(body);
-                                    v.hir_id
-                                } else {
-                                    None
-                                };
-                                if let Some(hir_id) = hir_id
-                                    && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
-                                {
-                                    let (changing, span, sugg) = match local.ty {
-                                        Some(ty) => ("changing", ty.span, message),
-                                        None => (
-                                            "specifying",
-                                            local.pat.span.shrink_to_hi(),
-                                            format!(": {message}"),
-                                        ),
-                                    };
-                                    err.span_suggestion_verbose(
-                                        span,
-                                        format!("consider {changing} this binding's type"),
-                                        sugg,
-                                        Applicability::HasPlaceholders,
-                                    );
-                                } else {
-                                    err.span_label(
-                                        err_label_span,
-                                        format!(
-                                            "consider changing this binding's type to be: `{message}`"
-                                        ),
-                                    );
-                                }
-                            }
-                            None => {}
-                        }
                         err.span_label(
                             span,
                             format!(
@@ -658,6 +485,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                  so the data it refers to cannot be {acted_on}",
                             ),
                         );
+
+                        self.suggest_make_local_mut(&mut err, local, name);
                     }
                     _ => {
                         err.span_label(
@@ -1131,6 +960,184 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
         }
     }
+
+    fn suggest_make_local_mut(
+        &self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        local: Local,
+        name: Symbol,
+    ) {
+        let local_decl = &self.body.local_decls[local];
+
+        let (pointer_sigil, pointer_desc) =
+            if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
+
+        let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
+        if is_trait_sig && local_trait.is_none() {
+            return;
+        }
+
+        let decl_span = match local_trait {
+            Some(span) => span,
+            None => local_decl.source_info.span,
+        };
+
+        let label = match *local_decl.local_info() {
+            LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
+                let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                Some((true, decl_span, suggestion))
+            }
+
+            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+                binding_mode: ty::BindingMode::BindByValue(_),
+                opt_ty_info,
+                ..
+            })) => {
+                // check if the RHS is from desugaring
+                let opt_assignment_rhs_span =
+                    self.body.find_assignments(local).first().map(|&location| {
+                        if let Some(mir::Statement {
+                            source_info: _,
+                            kind:
+                                mir::StatementKind::Assign(box (
+                                    _,
+                                    mir::Rvalue::Use(mir::Operand::Copy(place)),
+                                )),
+                        }) = self.body[location.block].statements.get(location.statement_index)
+                        {
+                            self.body.local_decls[place.local].source_info.span
+                        } else {
+                            self.body.source_info(location).span
+                        }
+                    });
+                match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
+                    // on for loops, RHS points to the iterator part
+                    Some(DesugaringKind::ForLoop) => {
+                        self.suggest_similar_mut_method_for_for_loop(err);
+                        err.span_label(
+                            opt_assignment_rhs_span.unwrap(),
+                            format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",),
+                        );
+                        None
+                    }
+                    // don't create labels for compiler-generated spans
+                    Some(_) => None,
+                    None => {
+                        let label = if name != kw::SelfLower {
+                            suggest_ampmut(
+                                self.infcx.tcx,
+                                local_decl.ty,
+                                decl_span,
+                                opt_assignment_rhs_span,
+                                opt_ty_info,
+                            )
+                        } else {
+                            match local_decl.local_info() {
+                                LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+                                    opt_ty_info: None,
+                                    ..
+                                })) => {
+                                    let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                                    (true, decl_span, sugg)
+                                }
+                                // explicit self (eg `self: &'a Self`)
+                                _ => suggest_ampmut(
+                                    self.infcx.tcx,
+                                    local_decl.ty,
+                                    decl_span,
+                                    opt_assignment_rhs_span,
+                                    opt_ty_info,
+                                ),
+                            }
+                        };
+                        Some(label)
+                    }
+                }
+            }
+
+            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+                binding_mode: ty::BindingMode::BindByReference(_),
+                ..
+            })) => {
+                let pattern_span: Span = local_decl.source_info.span;
+                suggest_ref_mut(self.infcx.tcx, pattern_span)
+                    .map(|span| (true, span, "mut ".to_owned()))
+            }
+
+            _ => unreachable!(),
+        };
+
+        match label {
+            Some((true, err_help_span, suggested_code)) => {
+                err.span_suggestion_verbose(
+                    err_help_span,
+                    format!("consider changing this to be a mutable {pointer_desc}"),
+                    suggested_code,
+                    Applicability::MachineApplicable,
+                );
+            }
+            Some((false, err_label_span, message)) => {
+                struct BindingFinder {
+                    span: Span,
+                    hir_id: Option<hir::HirId>,
+                }
+
+                impl<'tcx> Visitor<'tcx> for BindingFinder {
+                    fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+                        if let hir::StmtKind::Local(local) = s.kind {
+                            if local.pat.span == self.span {
+                                self.hir_id = Some(local.hir_id);
+                            }
+                        }
+                        hir::intravisit::walk_stmt(self, s);
+                    }
+                }
+                let hir_map = self.infcx.tcx.hir();
+                let def_id = self.body.source.def_id();
+                let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
+                let node = hir_map.find(hir_id);
+                let hir_id = if let Some(hir::Node::Item(item)) = node
+                && let hir::ItemKind::Fn(.., body_id) = item.kind
+            {
+                let body = hir_map.body(body_id);
+                let mut v = BindingFinder {
+                    span: err_label_span,
+                    hir_id: None,
+                };
+                v.visit_body(body);
+                v.hir_id
+            } else {
+                None
+            };
+                if let Some(hir_id) = hir_id
+                && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
+            {
+                let (changing, span, sugg) = match local.ty {
+                    Some(ty) => ("changing", ty.span, message),
+                    None => (
+                        "specifying",
+                        local.pat.span.shrink_to_hi(),
+                        format!(": {message}"),
+                    ),
+                };
+                err.span_suggestion_verbose(
+                    span,
+                    format!("consider {changing} this binding's type"),
+                    sugg,
+                    Applicability::HasPlaceholders,
+                );
+            } else {
+                err.span_label(
+                    err_label_span,
+                    format!(
+                        "consider changing this binding's type to be: `{message}`"
+                    ),
+                );
+            }
+            }
+            None => {}
+        }
+    }
 }
 
 pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
@@ -1160,25 +1167,18 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
     }
 }
 
-fn suggest_ampmut_self<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    local_decl: &mir::LocalDecl<'tcx>,
-) -> (Span, String) {
-    let sp = local_decl.source_info.span;
-    (
-        sp,
-        match tcx.sess.source_map().span_to_snippet(sp) {
-            Ok(snippet) => {
-                let lt_pos = snippet.find('\'');
-                if let Some(lt_pos) = lt_pos {
-                    format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
-                } else {
-                    "&mut self".to_string()
-                }
+fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
+    match tcx.sess.source_map().span_to_snippet(span) {
+        Ok(snippet) => {
+            let lt_pos = snippet.find('\'');
+            if let Some(lt_pos) = lt_pos {
+                format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
+            } else {
+                "&mut self".to_string()
             }
-            _ => "&mut self".to_string(),
-        },
-    )
+        }
+        _ => "&mut self".to_string(),
+    }
 }
 
 // When we want to suggest a user change a local variable to be a `&mut`, there
@@ -1198,72 +1198,89 @@ fn suggest_ampmut_self<'tcx>(
 // by trying (3.), then (2.) and finally falling back on (1.).
 fn suggest_ampmut<'tcx>(
     tcx: TyCtxt<'tcx>,
-    local_decl: &mir::LocalDecl<'tcx>,
+    decl_ty: Ty<'tcx>,
+    decl_span: Span,
     opt_assignment_rhs_span: Option<Span>,
     opt_ty_info: Option<Span>,
 ) -> (bool, Span, String) {
+    // if there is a RHS and it starts with a `&` from it, then check if it is
+    // mutable, and if not, put suggest putting `mut ` to make it mutable.
+    // we don't have to worry about lifetime annotations here because they are
+    // not valid when taking a reference. For example, the following is not valid Rust:
+    //
+    // let x: &i32 = &'a 5;
+    //                ^^ lifetime annotation not allowed
+    //
     if let Some(assignment_rhs_span) = opt_assignment_rhs_span
         && let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span)
+        && let Some(stripped) = src.strip_prefix('&')
     {
-        let is_mutbl = |ty: &str| -> bool {
-            if let Some(rest) = ty.strip_prefix("mut") {
-                match rest.chars().next() {
-                    // e.g. `&mut x`
-                    Some(c) if c.is_whitespace() => true,
-                    // e.g. `&mut(x)`
-                    Some('(') => true,
-                    // e.g. `&mut{x}`
-                    Some('{') => true,
-                    // e.g. `&mutablevar`
-                    _ => false,
-                }
-            } else {
-                false
+        let is_mut = if let Some(rest) = stripped.trim_start().strip_prefix("mut") {
+            match rest.chars().next() {
+                // e.g. `&mut x`
+                Some(c) if c.is_whitespace() => true,
+                // e.g. `&mut(x)`
+                Some('(') => true,
+                // e.g. `&mut{x}`
+                Some('{') => true,
+                // e.g. `&mutablevar`
+                _ => false,
             }
+        } else {
+            false
         };
-        if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
-            let lt_name = &src[1..ws_pos];
-            let ty = src[ws_pos..].trim_start();
-            if !is_mutbl(ty) {
-                return (true, assignment_rhs_span, format!("&{lt_name} mut {ty}"));
-            }
-        } else if let Some(stripped) = src.strip_prefix('&') {
-            let stripped = stripped.trim_start();
-            if !is_mutbl(stripped) {
-                return (true, assignment_rhs_span, format!("&mut {stripped}"));
-            }
+        // if the reference is already mutable then there is nothing we can do
+        // here.
+        if !is_mut {
+            let span = assignment_rhs_span;
+            // shrink the span to just after the `&` in `&variable`
+            let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
+
+            // FIXME(Ezrashaw): returning is bad because we still might want to
+            // update the annotated type, see #106857.
+            return (true, span, "mut ".to_owned());
         }
     }
 
-    let (suggestibility, highlight_span) = match opt_ty_info {
+    let (binding_exists, span) = match opt_ty_info {
         // if this is a variable binding with an explicit type,
-        // try to highlight that for the suggestion.
+        // then we will suggest changing it to be mutable.
+        // this is `Applicability::MachineApplicable`.
         Some(ty_span) => (true, ty_span),
 
-        // otherwise, just highlight the span associated with
-        // the (MIR) LocalDecl.
-        None => (false, local_decl.source_info.span),
+        // otherwise, we'll suggest *adding* an annotated type, we'll suggest
+        // the RHS's type for that.
+        // this is `Applicability::HasPlaceholders`.
+        None => (false, decl_span),
     };
 
-    if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span)
-        && let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace))
+    // if the binding already exists and is a reference with a explicit
+    // lifetime, then we can suggest adding ` mut`. this is special-cased from
+    // the path without a explicit lifetime.
+    if let Ok(src) = tcx.sess.source_map().span_to_snippet(span)
+        && src.starts_with("&'")
+        // note that `&     'a T` is invalid so this is correct.
+        && let Some(ws_pos) = src.find(char::is_whitespace)
     {
-        let lt_name = &src[1..ws_pos];
-        let ty = &src[ws_pos..];
-        return (true, highlight_span, format!("&{lt_name} mut{ty}"));
-    }
+        let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
+        (true, span, " mut".to_owned())
+    // if there is already a binding, we modify it to be `mut`
+    } else if binding_exists {
+        // shrink the span to just after the `&` in `&variable`
+        let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
+        (true, span, "mut ".to_owned())
+    } else {
+        // otherwise, suggest that the user annotates the binding; we provide the
+        // type of the local.
+        let ty_mut = decl_ty.builtin_deref(true).unwrap();
+        assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
 
-    let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
-    assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
-    (
-        suggestibility,
-        highlight_span,
-        if local_decl.ty.is_ref() {
-            format!("&mut {}", ty_mut.ty)
-        } else {
-            format!("*mut {}", ty_mut.ty)
-        },
-    )
+        (
+            false,
+            span,
+            format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty)
+        )
+    }
 }
 
 fn is_closure_or_generator(ty: Ty<'_>) -> bool {
@@ -1300,11 +1317,13 @@ fn get_mut_span_in_struct_field<'tcx>(
 }
 
 /// If possible, suggest replacing `ref` with `ref mut`.
-fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<String> {
-    let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?;
-    if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace) {
-        let replacement = format!("ref mut{}", &hi_src["ref".len()..]);
-        Some(replacement)
+fn suggest_ref_mut(tcx: TyCtxt<'_>, span: Span) -> Option<Span> {
+    let pattern_str = tcx.sess.source_map().span_to_snippet(span).ok()?;
+    if pattern_str.starts_with("ref")
+        && pattern_str["ref".len()..].starts_with(rustc_lexer::is_whitespace)
+    {
+        let span = span.with_lo(span.lo() + BytePos(4)).shrink_to_lo();
+        Some(span)
     } else {
         None
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 37cf3f30312..8ec872e2057 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -845,7 +845,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 return;
             }
 
-            let Some((alias_tys, alias_span)) = self
+            let Some((alias_tys, alias_span, lt_addition_span)) = self
                 .infcx
                 .tcx
                 .return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; };
@@ -858,10 +858,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     ()
                 }
                 if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
-                    spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
+                    if lt.ident.name == kw::Empty {
+                        spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
+                    } else {
+                        spans_suggs.push((lt.ident.span, "'a".to_string()));
+                    }
                 }
             }
-            spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
+
+            if let Some(lt_addition_span) = lt_addition_span {
+                spans_suggs.push((lt_addition_span, "'a, ".to_string()));
+            } else {
+                spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
+            }
+
             diag.multipart_suggestion_verbose(
                 format!(
                     "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias"
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 0d7cf7cdb26..3b458b1d30b 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -150,10 +150,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n ->
     *[more] arguments
     } in format string, but {$desc}
 
-builtin_macros_offset_of_expected_field = expected field
-
-builtin_macros_offset_of_expected_two_args = expected 2 arguments
-
 builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
 
 builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index e5a00331588..caced3d6447 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1038,7 +1038,7 @@ impl<'a> MethodDef<'a> {
     /// `&self.x` because that might cause an unaligned ref. So for any trait
     /// method that takes a reference, we use a local block to force a copy.
     /// This requires that the field impl `Copy`.
-    /// ```
+    /// ```rust,ignore (example)
     /// # struct A { x: u8, y: u8 }
     /// impl PartialEq for A {
     ///     fn eq(&self, other: &A) -> bool {
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index c7da61d72b3..4e5edb4d6b1 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -44,7 +44,6 @@ mod format;
 mod format_foreign;
 mod global_allocator;
 mod log_syntax;
-mod offset_of;
 mod source_util;
 mod test;
 mod trace_macros;
@@ -92,7 +91,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         line: source_util::expand_line,
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
-        offset_of: offset_of::expand_offset_of,
         option_env: env::expand_option_env,
         core_panic: edition_panic::expand_panic,
         std_panic: edition_panic::expand_panic,
diff --git a/compiler/rustc_builtin_macros/src/offset_of.rs b/compiler/rustc_builtin_macros/src/offset_of.rs
deleted file mode 100644
index 0ef3e000e41..00000000000
--- a/compiler/rustc_builtin_macros/src/offset_of.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use rustc_ast as ast;
-use rustc_ast::ptr::P;
-use rustc_ast::token;
-use rustc_ast::tokenstream::TokenStream;
-use rustc_errors::PResult;
-use rustc_expand::base::{self, *};
-use rustc_macros::Diagnostic;
-use rustc_parse::parser::Parser;
-use rustc_span::{symbol::Ident, Span};
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_offset_of_expected_field)]
-struct ExpectedField {
-    #[primary_span]
-    span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_offset_of_expected_two_args)]
-struct ExpectedTwoArgs {
-    #[primary_span]
-    span: Span,
-}
-
-fn parse_field<'a>(cx: &ExtCtxt<'a>, p: &mut Parser<'a>) -> PResult<'a, Ident> {
-    let token = p.token.uninterpolate();
-    let field = match token.kind {
-        token::Ident(name, _) => Ident::new(name, token.span),
-        token::Literal(token::Lit { kind: token::Integer, symbol, suffix: None }) => {
-            Ident::new(symbol, token.span)
-        }
-        _ => return Err(cx.create_err(ExpectedField { span: p.token.span })),
-    };
-
-    p.bump();
-
-    Ok(field)
-}
-
-fn parse_args<'a>(
-    cx: &mut ExtCtxt<'a>,
-    sp: Span,
-    tts: TokenStream,
-) -> PResult<'a, (P<ast::Ty>, P<[Ident]>)> {
-    let mut p = cx.new_parser_from_tts(tts);
-
-    let container = p.parse_ty()?;
-
-    p.expect(&token::Comma)?;
-
-    if p.eat(&token::Eof) {
-        return Err(cx.create_err(ExpectedTwoArgs { span: sp }));
-    }
-
-    let mut fields = Vec::new();
-
-    loop {
-        let field = parse_field(cx, &mut p)?;
-        fields.push(field);
-
-        if p.eat(&token::Dot) {
-            continue;
-        }
-
-        p.eat(&token::Comma);
-
-        if !p.eat(&token::Eof) {
-            return Err(cx.create_err(ExpectedTwoArgs { span: sp }));
-        }
-
-        break;
-    }
-
-    Ok((container, fields.into()))
-}
-
-pub fn expand_offset_of<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    match parse_args(cx, sp, tts) {
-        Ok((container, fields)) => {
-            let expr = P(ast::Expr {
-                id: ast::DUMMY_NODE_ID,
-                kind: ast::ExprKind::OffsetOf(container, fields),
-                span: sp,
-                attrs: ast::AttrVec::new(),
-                tokens: None,
-            });
-
-            MacEager::expr(expr)
-        }
-        Err(mut err) => {
-            err.emit();
-            DummyResult::any(sp)
-        }
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 264b95e7abd..ccb3a0c4f27 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -361,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.tcx,
             ty::ParamEnv::reveal_all(),
-            value,
+            ty::EarlyBinder(value),
         )
     }
 
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index a66ddb6a09f..869344ce92d 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1227,6 +1227,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         (value1, value2)
     }
 
+    fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
+        // TODO(antoyo): generate the correct landing pad
+        self.cleanup_landing_pad(pers_fn)
+    }
+
     #[cfg(feature="master")]
     fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) {
         let exn_type = exn0.get_type();
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index f9af103c9ad..2a6ad1be763 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -236,9 +236,22 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 InlineAsmArch::Nvptx64 => {}
                 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
                 InlineAsmArch::Hexagon => {}
-                InlineAsmArch::LoongArch64 => {}
+                InlineAsmArch::LoongArch64 => {
+                    constraints.extend_from_slice(&[
+                        "~{$fcc0}".to_string(),
+                        "~{$fcc1}".to_string(),
+                        "~{$fcc2}".to_string(),
+                        "~{$fcc3}".to_string(),
+                        "~{$fcc4}".to_string(),
+                        "~{$fcc5}".to_string(),
+                        "~{$fcc6}".to_string(),
+                        "~{$fcc7}".to_string(),
+                    ]);
+                }
                 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
-                InlineAsmArch::S390x => {}
+                InlineAsmArch::S390x => {
+                    constraints.push("~{cc}".to_string());
+                }
                 InlineAsmArch::SpirV => {}
                 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
                 InlineAsmArch::Bpf => {}
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 2fd6db8cbfe..4d0bcd53d15 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -985,13 +985,20 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
     fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
         let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
-        let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */);
+        let landing_pad = self.landing_pad(ty, pers_fn, 0);
         unsafe {
             llvm::LLVMSetCleanup(landing_pad, llvm::True);
         }
         (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
     }
 
+    fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
+        let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
+        let landing_pad = self.landing_pad(ty, pers_fn, 1);
+        self.add_clause(landing_pad, self.const_array(self.type_i8p(), &[]));
+        (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
+    }
+
     fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) {
         let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
         let mut exn = self.const_poison(ty);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 2f910c37d61..3fff112a020 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>(
             let callee = cx.tcx.subst_and_normalize_erasing_regions(
                 instance.substs,
                 ty::ParamEnv::reveal_all(),
-                callee,
+                ty::EarlyBinder(callee),
             );
             let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
             cx.dbg_scope_fn(callee, callee_fn_abi, None)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index b138b0c0e70..c3f0a0033b0 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -529,7 +529,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
                         instance.substs,
                         ty::ParamEnv::reveal_all(),
-                        cx.tcx.type_of(impl_def_id).skip_binder(),
+                        cx.tcx.type_of(impl_def_id),
                     );
 
                     // Only "class" methods are generally understood by LLVM,
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index d5d843702c0..8968133bac5 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -12,6 +12,7 @@ use object::{
 
 use snap::write::FrameEncoder;
 
+use object::elf::NT_GNU_PROPERTY_TYPE_0;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owned_slice::try_slice_owned;
 use rustc_data_structures::sync::MetadataRef;
@@ -93,6 +94,54 @@ pub(super) fn search_for_section<'a>(
         .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
 }
 
+fn add_gnu_property_note(
+    file: &mut write::Object<'static>,
+    architecture: Architecture,
+    binary_format: BinaryFormat,
+    endianness: Endianness,
+) {
+    // check bti protection
+    if binary_format != BinaryFormat::Elf
+        || !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64)
+    {
+        return;
+    }
+
+    let section = file.add_section(
+        file.segment_name(StandardSegment::Data).to_vec(),
+        b".note.gnu.property".to_vec(),
+        SectionKind::Note,
+    );
+    let mut data: Vec<u8> = Vec::new();
+    let n_namsz: u32 = 4; // Size of the n_name field
+    let n_descsz: u32 = 16; // Size of the n_desc field
+    let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
+    let header_values = [n_namsz, n_descsz, n_type];
+    header_values.iter().for_each(|v| {
+        data.extend_from_slice(&match endianness {
+            Endianness::Little => v.to_le_bytes(),
+            Endianness::Big => v.to_be_bytes(),
+        })
+    });
+    data.extend_from_slice(b"GNU\0"); // Owner of the program property note
+    let pr_type: u32 = match architecture {
+        Architecture::X86_64 => 0xc0000002,
+        Architecture::Aarch64 => 0xc0000000,
+        _ => unreachable!(),
+    };
+    let pr_datasz: u32 = 4; //size of the pr_data field
+    let pr_data: u32 = 3; //program property descriptor
+    let pr_padding: u32 = 0;
+    let property_values = [pr_type, pr_datasz, pr_data, pr_padding];
+    property_values.iter().for_each(|v| {
+        data.extend_from_slice(&match endianness {
+            Endianness::Little => v.to_le_bytes(),
+            Endianness::Big => v.to_be_bytes(),
+        })
+    });
+    file.append_section_data(section, &data, 8);
+}
+
 pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
     let endianness = match sess.target.options.endian {
         Endian::Little => Endianness::Little,
@@ -205,6 +254,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
         _ => elf::ELFOSABI_NONE,
     };
     let abi_version = 0;
+    add_gnu_property_note(&mut file, architecture, binary_format, endianness);
     file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
     Some(file)
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index c1613a9640a..a832999225a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1600,7 +1600,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx = Bx::build(self.cx, llbb);
 
                 let llpersonality = self.cx.eh_personality();
-                bx.cleanup_landing_pad(llpersonality);
+                bx.filter_landing_pad(llpersonality);
 
                 funclet = None;
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index f706ecea975..1204c99e533 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.cx.tcx(),
             ty::ParamEnv::reveal_all(),
-            value,
+            ty::EarlyBinder(value),
         )
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 57de7e9620e..853c6934c2c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -274,6 +274,7 @@ pub trait BuilderMethods<'a, 'tcx>:
 
     // These are used by everyone except msvc
     fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
+    fn filter_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
     fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
 
     // These are used only by msvc
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 361ce123c78..b2197a0aabb 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -495,7 +495,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> Result<T, InterpError<'tcx>> {
         frame
             .instance
-            .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
+            .try_subst_mir_and_normalize_erasing_regions(
+                *self.tcx,
+                self.param_env,
+                ty::EarlyBinder(value),
+            )
             .map_err(|_| err_inval!(TooGeneric))
     }
 
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 572bd4ac21c..5e13e7c8aaf 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -101,7 +101,7 @@ use parking_lot::RwLock;
 use smallvec::SmallVec;
 
 bitflags::bitflags! {
-    struct EventFilter: u32 {
+    struct EventFilter: u16 {
         const GENERIC_ACTIVITIES  = 1 << 0;
         const QUERY_PROVIDERS     = 1 << 1;
         const QUERY_CACHE_HITS    = 1 << 2;
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index cc4c5a0cacd..d7d97fcc3e7 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -51,6 +51,7 @@ rustc_interface = { path = "../rustc_interface" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_mir_transform = { path = "../rustc_mir_transform" }
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
@@ -64,5 +65,8 @@ features = [
 [features]
 llvm = ['rustc_interface/llvm']
 max_level_info = ['rustc_log/max_level_info']
-rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
-    'rustc_middle/rustc_use_parallel_compiler']
+rustc_use_parallel_compiler = [
+    'rustc_data_structures/rustc_use_parallel_compiler',
+    'rustc_interface/rustc_use_parallel_compiler',
+    'rustc_middle/rustc_use_parallel_compiler'
+]
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 405f3d5b66d..9b16f246193 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -99,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
     rustc_middle::DEFAULT_LOCALE_RESOURCE,
     rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
     rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
+    rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
     rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
     rustc_parse::DEFAULT_LOCALE_RESOURCE,
     rustc_passes::DEFAULT_LOCALE_RESOURCE,
@@ -745,6 +746,22 @@ fn print_crate_info(
                     }
                 }
             }
+            DeploymentTarget => {
+                use rustc_target::spec::current_apple_deployment_target;
+
+                if sess.target.is_like_osx {
+                    safe_println!(
+                        "deployment_target={}",
+                        current_apple_deployment_target(&sess.target)
+                            .expect("unknown Apple target OS")
+                    )
+                } else {
+                    early_error(
+                        ErrorOutputType::default(),
+                        "only Apple targets currently support deployment version info",
+                    )
+                }
+            }
         }
     }
     Compilation::Stop
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index ef528d87cb2..db97d96fccd 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -571,6 +571,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
         Some((diagnostic, handler))
     }
 
+    /// Retrieves the [`Handler`] if available
+    pub fn handler(&self) -> Option<&Handler> {
+        match self.inner.state {
+            DiagnosticBuilderState::Emittable(handler) => Some(handler),
+            DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
+        }
+    }
+
     /// Buffers the diagnostic for later emission,
     /// unless handler has disabled such buffering.
     pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 27d30c315af..f4615445f8e 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -313,6 +313,8 @@ declare_features! (
     (active, async_closure, "1.37.0", Some(62290), None),
     /// Allows async functions to be declared, implemented, and used in traits.
     (active, async_fn_in_trait, "1.66.0", Some(91611), None),
+    /// Allows builtin # foo() syntax
+    (active, builtin_syntax, "CURRENT_RUSTC_VERSION", Some(110680), None),
     /// Allows `c"foo"` literals.
     (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None),
     /// Treat `extern "C"` function as nounwind.
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index b70a55e8953..5d86d895817 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -167,7 +167,7 @@
 //!     fn node_label(&self, n: &Nd) -> dot::LabelText<'_> {
 //!         dot::LabelText::LabelStr(self.nodes[*n].into())
 //!     }
-//!     fn edge_label<'b>(&'b self, _: &Ed) -> dot::LabelText<'b> {
+//!     fn edge_label(&self, _: &Ed<'_>) -> dot::LabelText<'_> {
 //!         dot::LabelText::LabelStr("&sube;".into())
 //!     }
 //! }
@@ -177,8 +177,8 @@
 //!     type Edge = Ed<'a>;
 //!     fn nodes(&self) -> dot::Nodes<'a,Nd> { (0..self.nodes.len()).collect() }
 //!     fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> { self.edges.iter().collect() }
-//!     fn source(&self, e: &Ed) -> Nd { let & &(s,_) = e; s }
-//!     fn target(&self, e: &Ed) -> Nd { let & &(_,t) = e; t }
+//!     fn source(&self, e: &Ed<'_>) -> Nd { let & &(s,_) = e; s }
+//!     fn target(&self, e: &Ed<'_>) -> Nd { let & &(_,t) = e; t }
 //! }
 //!
 //! # pub fn main() { render_to(&mut Vec::new()) }
@@ -226,11 +226,11 @@
 //!     fn node_id(&'a self, n: &Nd<'a>) -> dot::Id<'a> {
 //!         dot::Id::new(format!("N{}", n.0)).unwrap()
 //!     }
-//!     fn node_label<'b>(&'b self, n: &Nd<'b>) -> dot::LabelText<'b> {
+//!     fn node_label(&self, n: &Nd<'_>) -> dot::LabelText<'_> {
 //!         let &(i, _) = n;
 //!         dot::LabelText::LabelStr(self.nodes[i].into())
 //!     }
-//!     fn edge_label<'b>(&'b self, _: &Ed<'b>) -> dot::LabelText<'b> {
+//!     fn edge_label(&self, _: &Ed<'_>) -> dot::LabelText<'_> {
 //!         dot::LabelText::LabelStr("&sube;".into())
 //!     }
 //! }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 5ee0cf94360..6ac1df6a079 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2419,6 +2419,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return Ok(None);
         }
 
+        //
+        // Select applicable inherent associated type candidates modulo regions.
+        //
+
         // In contexts that have no inference context, just make a new one.
         // We do need a local variable to store it, though.
         let infcx_;
@@ -2431,7 +2435,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         };
 
-        let param_env = tcx.param_env(block.owner.to_def_id());
+        // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
+        // when inside of an ADT (#108491) or where clause.
+        let param_env = tcx.param_env(block.owner);
         let cause = ObligationCause::misc(span, block.owner.def_id);
 
         let mut fulfillment_errors = Vec::new();
@@ -2439,6 +2445,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let universe = infcx.create_next_universe();
 
             // Regions are not considered during selection.
+            // FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes
+            // of type and const binders. Is that correct in the selection phase? See also #109505.
             let self_ty = tcx.replace_escaping_bound_vars_uncached(
                 self_ty,
                 FnMutDelegate {
@@ -2454,41 +2462,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
             candidates
                 .iter()
-                .filter_map(|&(impl_, (assoc_item, def_scope))| {
+                .copied()
+                .filter(|&(impl_, _)| {
                     infcx.probe(|_| {
                         let ocx = ObligationCtxt::new_in_snapshot(&infcx);
 
-                        let impl_ty = tcx.type_of(impl_);
                         let impl_substs = infcx.fresh_item_substs(impl_);
-                        let impl_ty = impl_ty.subst(tcx, impl_substs);
+                        let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs);
                         let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
 
-                        // Check that the Self-types can be related.
-                        // FIXME(fmease): Should we use `eq` here?
-                        ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
+                        // Check that the self types can be related.
+                        // FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses
+                        // `sup` for this situtation, too. What for? To constrain inference variables?
+                        if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err()
+                        {
+                            return false;
+                        }
 
                         // Check whether the impl imposes obligations we have to worry about.
-                        let impl_bounds = tcx.predicates_of(impl_);
-                        let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
-
+                        let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_substs);
                         let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
-
                         let impl_obligations = traits::predicates_for_generics(
                             |_, _| cause.clone(),
                             param_env,
                             impl_bounds,
                         );
-
                         ocx.register_obligations(impl_obligations);
 
                         let mut errors = ocx.select_where_possible();
                         if !errors.is_empty() {
                             fulfillment_errors.append(&mut errors);
-                            return None;
+                            return false;
                         }
 
-                        // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
-                        Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
+                        true
                     })
                 })
                 .collect()
@@ -2497,24 +2504,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         if applicable_candidates.len() > 1 {
             return Err(self.complain_about_ambiguous_inherent_assoc_type(
                 name,
-                applicable_candidates.into_iter().map(|(candidate, ..)| candidate).collect(),
+                applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
                 span,
             ));
         }
 
-        if let Some((assoc_item, def_scope, impl_substs)) = applicable_candidates.pop() {
+        if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() {
             self.check_assoc_ty(assoc_item, name, def_scope, block, span);
 
-            // FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still
-            // need to relate the Self-type with fresh item substs & register region obligations for
-            // regionck to prove/disprove.
-
-            let item_substs =
-                self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs);
+            // FIXME(fmease): Currently creating throwaway `parent_substs` to please
+            // `create_substs_for_associated_item`. Modify the latter instead (or sth. similar) to
+            // not require the parent substs logic.
+            let parent_substs = InternalSubsts::identity_for_item(tcx, impl_);
+            let substs =
+                self.create_substs_for_associated_item(span, assoc_item, segment, parent_substs);
+            let substs = tcx.mk_substs_from_iter(
+                std::iter::once(ty::GenericArg::from(self_ty))
+                    .chain(substs.into_iter().skip(parent_substs.len())),
+            );
 
-            // FIXME(fmease, #106722): Check if the bounds on the parameters of the
-            // associated type hold, if any.
-            let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
+            let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
 
             return Ok(Some((ty, assoc_item)));
         }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 7384eb25f2e..8bf1e0e84a4 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -60,19 +60,21 @@ pub(super) fn compare_impl_method<'tcx>(
     };
 }
 
-/// This function is best explained by example. Consider a trait:
+/// This function is best explained by example. Consider a trait with it's implementation:
 ///
-///     trait Trait<'t, T> {
-///         // `trait_m`
-///         fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
-///     }
+/// ```rust
+/// trait Trait<'t, T> {
+///     // `trait_m`
+///     fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
+/// }
 ///
-/// And an impl:
+/// struct Foo;
 ///
-///     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
-///          // `impl_m`
-///          fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
-///     }
+/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
+///     // `impl_m`
+///     fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo { Foo }
+/// }
+/// ```
 ///
 /// We wish to decide if those two method types are compatible.
 /// For this we have to show that, assuming the bounds of the impl hold, the
@@ -82,7 +84,9 @@ pub(super) fn compare_impl_method<'tcx>(
 /// type parameters to impl type parameters. This is taken from the
 /// impl trait reference:
 ///
-///     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+/// ```rust,ignore (pseudo-Rust)
+/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+/// ```
 ///
 /// We create a mapping `dummy_substs` that maps from the impl type
 /// parameters to fresh types and regions. For type parameters,
@@ -91,13 +95,17 @@ pub(super) fn compare_impl_method<'tcx>(
 /// regions (Note: but only early-bound regions, i.e., those
 /// declared on the impl or used in type parameter bounds).
 ///
-///     impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
+/// ```rust,ignore (pseudo-Rust)
+/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
+/// ```
 ///
 /// Now we can apply `placeholder_substs` to the type of the impl method
 /// to yield a new function type in terms of our fresh, placeholder
 /// types:
 ///
-///     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+/// ```rust,ignore (pseudo-Rust)
+/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+/// ```
 ///
 /// We now want to extract and substitute the type of the *trait*
 /// method and compare it. To do so, we must create a compound
@@ -106,11 +114,15 @@ pub(super) fn compare_impl_method<'tcx>(
 /// type parameters. We extend the mapping to also include
 /// the method parameters.
 ///
-///     trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+/// ```rust,ignore (pseudo-Rust)
+/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+/// ```
 ///
 /// Applying this to the trait method type yields:
 ///
-///     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+/// ```rust,ignore (pseudo-Rust)
+/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+/// ```
 ///
 /// This type is also the same but the name of the bound region (`'a`
 /// vs `'b`). However, the normal subtyping rules on fn types handle
@@ -1163,7 +1175,7 @@ fn compare_self_type<'tcx>(
 /// as the number of generics on the respective assoc item in the trait definition.
 ///
 /// For example this code emits the errors in the following code:
-/// ```
+/// ```rust,compile_fail
 /// trait Trait {
 ///     fn foo();
 ///     type Assoc<T>;
@@ -1547,7 +1559,7 @@ fn compare_synthetic_generics<'tcx>(
 /// the same kind as the respective generic parameter in the trait def.
 ///
 /// For example all 4 errors in the following code are emitted here:
-/// ```
+/// ```rust,ignore (pseudo-Rust)
 /// trait Foo {
 ///     fn foo<const N: u8>();
 ///     type bar<const N: u8>;
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 5ce8a83aad7..272177dfbd0 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -210,6 +210,19 @@ fn do_orphan_check_impl<'tcx>(
                 NonlocalImpl::DisallowOther,
             ),
 
+            // ```
+            // struct S<T>(T);
+            // impl<T: ?Sized> S<T> {
+            //     type This = T;
+            // }
+            // impl<T: ?Sized> AutoTrait for S<T>::This {}
+            // ```
+            // FIXME(inherent_associated_types): The example code above currently leads to a cycle
+            ty::Alias(AliasKind::Inherent, _) => (
+                LocalImpl::Disallow { problematic_kind: "associated type" },
+                NonlocalImpl::DisallowOther,
+            ),
+
             // type Opaque = impl Trait;
             // impl AutoTrait for Opaque {}
             ty::Alias(AliasKind::Opaque, _) => (
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 6c06957d1ee..e04658c8e77 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -657,14 +657,15 @@ pub(super) fn implied_predicates_with_filter(
         &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match));
     debug!(?implied_bounds);
 
-    // Now require that immediate supertraits are converted,
-    // which will, in turn, reach indirect supertraits.
+    // Now require that immediate supertraits are converted, which will, in
+    // turn, reach indirect supertraits, so we detect cycles now instead of
+    // overflowing during elaboration.
     if matches!(filter, PredicateFilter::SelfOnly) {
-        // Now require that immediate supertraits are converted,
-        // which will, in turn, reach indirect supertraits.
         for &(pred, span) in implied_bounds {
             debug!("superbound: {:?}", pred);
-            if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() {
+            if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder()
+                && bound.polarity == ty::ImplPolarity::Positive
+            {
                 tcx.at(span).super_predicates_of(bound.def_id());
             }
         }
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 ab0dd01ce3a..5c7f7f10b17 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1923,7 +1923,7 @@ fn is_late_bound_map(
     /// handles cycle detection as we go through the query system.
     ///
     /// This is necessary in the first place for the following case:
-    /// ```
+    /// ```rust,ignore (pseudo-Rust)
     /// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
     /// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
     /// ```
@@ -1948,7 +1948,7 @@ fn is_late_bound_map(
                 ty::Param(param_ty) => {
                     self.arg_is_constrained[param_ty.index as usize] = true;
                 }
-                ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()),
+                ty::Alias(ty::Projection | ty::Inherent, _) => return ControlFlow::Continue(()),
                 _ => (),
             }
             t.super_visit_with(self)
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index c20fbfd1e40..8df0166f76b 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -127,7 +127,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             // the def_id that this query was called with. We filter to only type and const args here
             // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
             // but it can't hurt to be safe ^^
-            if let ty::Alias(ty::Projection, projection) = ty.kind() {
+            if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() {
                 let generics = tcx.generics_of(projection.def_id);
 
                 let arg_index = segment
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index e18b0f08279..9200c2aecf5 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -59,7 +59,7 @@ struct ParameterCollector {
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
-            ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
+            ty::Alias(ty::Projection | ty::Inherent, ..) if !self.include_nonconstraining => {
                 // projections are not injective
                 return ControlFlow::Continue(());
             }
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index d53c429ca15..0cd2fc1aa29 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -210,6 +210,9 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 );
             }
 
+            // FIXME(inherent_associated_types): Handle this case properly.
+            ty::Alias(ty::Inherent, _) => {}
+
             _ => {}
         }
     }
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 603ea1440e9..aa664031a87 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -75,3 +75,7 @@ hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
 
 hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where
     .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new
+
+hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+
+hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new`
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index ee81ea345a6..2defca54aff 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -51,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
             || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
             || self.suggest_no_capture_closure(err, expected, expr_ty)
-            || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
+            || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty)
             || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
             || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
             || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
@@ -86,9 +86,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
-        self.check_for_range_as_method_call(err, expr, expr_ty, expected);
-        self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
-        self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
+        self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected);
+        self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected);
+        self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
     }
 
     /// Requires that the two types unify, and prints an error message if
@@ -1087,7 +1087,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// ```ignore (illustrative)
     /// opt.map(|param| { takes_ref(param) });
     /// ```
-    fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, String)> {
+    fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> {
         let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else {
             return None;
         };
@@ -1133,12 +1133,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => false,
         };
-        match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
-            (true, Ok(src)) => {
-                let suggestion = format!("as_ref().{}", src);
-                Some((method_path.ident.span, "consider using `as_ref` instead", suggestion))
-            }
-            _ => None,
+        if is_as_ref_able {
+            Some((
+                vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())],
+                "consider using `as_ref` instead",
+            ))
+        } else {
+            None
         }
     }
 
@@ -1217,14 +1218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// In addition of this check, it also checks between references mutability state. If the
     /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
     /// `&mut`!".
-    pub fn check_ref(
+    pub fn suggest_deref_or_ref(
         &self,
         expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> Option<(
-        Span,
-        String,
+        Vec<(Span, String)>,
         String,
         Applicability,
         bool, /* verbose */
@@ -1254,30 +1254,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         && let Ok(src) = sm.span_to_snippet(sp)
                         && replace_prefix(&src, "b\"", "\"").is_some()
                     {
-                                let pos = sp.lo() + BytePos(1);
-                                return Some((
-                                    sp.with_hi(pos),
-                                    "consider removing the leading `b`".to_string(),
-                                    String::new(),
-                                    Applicability::MachineApplicable,
-                                    true,
-                                    false,
-                                ));
-                            }
-                        }
+                        let pos = sp.lo() + BytePos(1);
+                        return Some((
+                            vec![(sp.with_hi(pos), String::new())],
+                            "consider removing the leading `b`".to_string(),
+                            Applicability::MachineApplicable,
+                            true,
+                            false,
+                        ));
+                    }
+                }
                 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
                     if let hir::ExprKind::Lit(_) = expr.kind
                         && let Ok(src) = sm.span_to_snippet(sp)
                         && replace_prefix(&src, "\"", "b\"").is_some()
                     {
-                                return Some((
-                                    sp.shrink_to_lo(),
-                                    "consider adding a leading `b`".to_string(),
-                                    "b".to_string(),
-                                    Applicability::MachineApplicable,
-                                    true,
-                                    false,
-                                ));
+                        return Some((
+                            vec![(sp.shrink_to_lo(), "b".to_string())],
+                            "consider adding a leading `b`".to_string(),
+                            Applicability::MachineApplicable,
+                            true,
+                            false,
+                        ));
                     }
                 }
                 _ => {}
@@ -1320,66 +1318,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind
-                        && let Some(1) = self.deref_steps(expected, checked_ty) {
+                        && let Some(1) = self.deref_steps(expected, checked_ty)
+                    {
                         // We have `*&T`, check if what was expected was `&T`.
                         // If so, we may want to suggest removing a `*`.
                         sugg_sp = sugg_sp.with_hi(inner.span.lo());
                         return Some((
-                            sugg_sp,
+                            vec![(sugg_sp, String::new())],
                             "consider removing deref here".to_string(),
-                            "".to_string(),
                             Applicability::MachineApplicable,
                             true,
                             false,
                         ));
                     }
 
-                    if let Ok(src) = sm.span_to_snippet(sugg_sp) {
-                        let needs_parens = match expr.kind {
-                            // parenthesize if needed (Issue #46756)
-                            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
-                            // parenthesize borrows of range literals (Issue #54505)
-                            _ if is_range_literal(expr) => true,
-                            _ => false,
-                        };
-
-                        if let Some(sugg) = self.can_use_as_ref(expr) {
-                            return Some((
-                                sugg.0,
-                                sugg.1.to_string(),
-                                sugg.2,
-                                Applicability::MachineApplicable,
-                                false,
-                                false,
-                            ));
-                        }
-
-                        let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
-                            Some(ident) => format!("{ident}: "),
-                            None => String::new(),
-                        };
-
-                        if let Some(hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Assign(..),
-                            ..
-                        })) = self.tcx.hir().find_parent(expr.hir_id)
-                        {
-                            if mutability.is_mut() {
-                                // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
-                                return None;
-                            }
-                        }
+                    let needs_parens = match expr.kind {
+                        // parenthesize if needed (Issue #46756)
+                        hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+                        // parenthesize borrows of range literals (Issue #54505)
+                        _ if is_range_literal(expr) => true,
+                        _ => false,
+                    };
 
-                        let sugg_expr = if needs_parens { format!("({src})") } else { src };
+                    if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
                         return Some((
-                            sp,
-                            format!("consider {}borrowing here", mutability.mutably_str()),
-                            format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()),
+                            sugg,
+                            msg.to_string(),
                             Applicability::MachineApplicable,
-                            false,
+                            true,
                             false,
                         ));
                     }
+
+                    let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                        Some(ident) => format!("{ident}: "),
+                        None => String::new(),
+                    };
+
+                    if let Some(hir::Node::Expr(hir::Expr {
+                        kind: hir::ExprKind::Assign(..),
+                        ..
+                    })) = self.tcx.hir().find_parent(expr.hir_id)
+                    {
+                        if mutability.is_mut() {
+                            // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
+                            return None;
+                        }
+                    }
+
+                    let sugg = mutability.ref_prefix_str();
+                    let (sugg, verbose) = if needs_parens {
+                        (
+                            vec![
+                                (sp.shrink_to_lo(), format!("{prefix}{sugg}(")),
+                                (sp.shrink_to_hi(), ")".to_string()),
+                            ],
+                            false,
+                        )
+                    } else {
+                        (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true)
+                    };
+                    return Some((
+                        sugg,
+                        format!("consider {}borrowing here", mutability.mutably_str()),
+                        Applicability::MachineApplicable,
+                        verbose,
+                        false,
+                    ));
                 }
             }
             (
@@ -1401,23 +1406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         && sm.is_span_accessible(call_span)
                     {
                         return Some((
-                            sp.with_hi(call_span.lo()),
+                            vec![(sp.with_hi(call_span.lo()), String::new())],
                             "consider removing the borrow".to_string(),
-                            String::new(),
                             Applicability::MachineApplicable,
                             true,
-                            true
+                            true,
                         ));
                     }
                     return None;
                 }
-                if sp.contains(expr.span)
-                    && sm.is_span_accessible(expr.span)
-                {
+                if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
                     return Some((
-                        sp.with_hi(expr.span.lo()),
+                        vec![(sp.with_hi(expr.span.lo()), String::new())],
                         "consider removing the borrow".to_string(),
-                        String::new(),
                         Applicability::MachineApplicable,
                         true,
                         true,
@@ -1441,23 +1442,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
                         // skip `&` or `&mut ` if both mutabilities are mutable
-                        let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
+                        let lo = sp.lo()
+                            + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
                         // skip `&` or `&mut `
                         let hi = sp.lo() + BytePos(old_prefix.len() as _);
                         let sp = sp.with_lo(lo).with_hi(hi);
 
                         (
                             sp,
-                            format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }),
-                            if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }
+                            format!(
+                                "{}{derefs}",
+                                if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }
+                            ),
+                            if mutbl_b <= mutbl_a {
+                                Applicability::MachineApplicable
+                            } else {
+                                Applicability::MaybeIncorrect
+                            },
                         )
                     });
 
                     if let Some((span, src, applicability)) = suggestion {
                         return Some((
-                            span,
+                            vec![(span, src)],
                             "consider dereferencing".to_string(),
-                            src,
                             applicability,
                             true,
                             false,
@@ -1486,9 +1494,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // If we've reached our target type with just removing `&`, then just print now.
                     if steps == 0 && !remove.trim().is_empty() {
                         return Some((
-                            prefix_span,
+                            vec![(prefix_span, String::new())],
                             format!("consider removing the `{}`", remove.trim()),
-                            String::new(),
                             // Do not remove `&&` to get to bool, because it might be something like
                             // { a } && b, which we have a separate fixup suggestion that is more
                             // likely correct...
@@ -1554,9 +1561,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
 
                         return Some((
-                            span,
+                            vec![(span, suggestion)],
                             message,
-                            suggestion,
                             Applicability::MachineApplicable,
                             true,
                             false,
@@ -1569,7 +1575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         None
     }
 
-    pub fn check_for_cast(
+    pub fn suggest_cast(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
@@ -1936,7 +1942,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
-    pub fn check_for_range_as_method_call(
+    pub fn suggest_method_call_on_range_literal(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'tcx>,
@@ -2005,7 +2011,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Identify when the type error is because `()` is found in a binding that was assigned a
     /// block without a tail expression.
-    fn check_for_binding_assigned_block_without_tail_expression(
+    fn suggest_return_binding_for_missing_tail_expr(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
@@ -2047,7 +2053,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_wrong_return_type_due_to_generic_arg(
+    fn note_wrong_return_ty_due_to_generic_arg(
         &self,
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 48c40d21603..ce30bbeca0b 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -267,3 +267,31 @@ pub struct ArgMismatchIndeterminate {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Subdiagnostic)]
+pub enum SuggestBoxing {
+    #[note(hir_typeck_suggest_boxing_note)]
+    #[multipart_suggestion(
+        hir_typeck_suggest_boxing_when_appropriate,
+        applicability = "machine-applicable"
+    )]
+    Unit {
+        #[suggestion_part(code = "Box::new(())")]
+        start: Span,
+        #[suggestion_part(code = "")]
+        end: Span,
+    },
+    #[note(hir_typeck_suggest_boxing_note)]
+    AsyncBody,
+    #[note(hir_typeck_suggest_boxing_note)]
+    #[multipart_suggestion(
+        hir_typeck_suggest_boxing_when_appropriate,
+        applicability = "machine-applicable"
+    )]
+    Other {
+        #[suggestion_part(code = "Box::new(")]
+        start: Span,
+        #[suggestion_part(code = ")")]
+        end: Span,
+    },
+}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 70ce45e21ea..05e5d850bf9 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -843,7 +843,7 @@ fn find_param_in_ty<'tcx>(
             return true;
         }
         if let ty::GenericArgKind::Type(ty) = arg.unpack()
-                && let ty::Alias(ty::Projection, ..) = ty.kind()
+                && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
             {
                 // This logic may seem a bit strange, but typically when
                 // we have a projection type in a function signature, the
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 4b8fc7303a2..c7011b23a7d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1519,7 +1519,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // case we can ignore the tail expression (e.g., `'a: {
         // break 'a 22; }` would not force the type of the block
         // to be `()`).
-        let tail_expr = blk.expr.as_ref();
         let coerce_to_ty = expected.coercion_target_type(self, blk.span);
         let coerce = if blk.targeted_by_break {
             CoerceMany::new(coerce_to_ty)
@@ -1537,13 +1536,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // check the tail expression **without** holding the
             // `enclosing_breakables` lock below.
-            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+            let tail_expr_ty =
+                blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected)));
 
             let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
             let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
             let coerce = ctxt.coerce.as_mut().unwrap();
-            if let Some(tail_expr_ty) = tail_expr_ty {
-                let tail_expr = tail_expr.unwrap();
+            if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty {
                 let span = self.get_expr_coercion_span(tail_expr);
                 let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
                 let ty_for_diagnostic = coerce.merged_ty();
@@ -1596,6 +1595,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         &self.misc(sp),
                         &mut |err| {
                             if let Some(expected_ty) = expected.only_has_type(self) {
+                                if blk.stmts.is_empty() && blk.expr.is_none() {
+                                    self.suggest_boxing_when_appropriate(
+                                        err,
+                                        blk.span,
+                                        blk.hir_id,
+                                        expected_ty,
+                                        self.tcx.mk_unit(),
+                                    );
+                                }
                                 if !self.consider_removing_semicolon(blk, expected_ty, err) {
                                     self.err_ctxt().consider_returning_binding(
                                         blk,
@@ -1608,7 +1616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     // silence this redundant error, as we already emit E0070.
 
                                     // Our block must be a `assign desugar local; assignment`
-                                    if let Some(hir::Node::Block(hir::Block {
+                                    if let hir::Block {
                                         stmts:
                                             [
                                                 hir::Stmt {
@@ -1630,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                                 },
                                             ],
                                         ..
-                                    })) = self.tcx.hir().find(blk.hir_id)
+                                    } = blk
                                     {
                                         self.comes_from_while_condition(blk.hir_id, |_| {
                                             err.downgrade_to_delayed_bug();
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 73a7bbebb65..67f45f9aa3f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -300,7 +300,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         match ty.kind() {
             ty::Adt(adt_def, _) => Some(*adt_def),
             // FIXME(#104767): Should we handle bound regions here?
-            ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
+            ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => {
                 self.normalize(span, ty).ty_adt_def()
             }
             _ => None,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 8978139119c..c4add4dbdfb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,6 +1,6 @@
 use super::FnCtxt;
 
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing};
 use crate::fluent_generated as fluent;
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -9,7 +9,8 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
+    AsyncGeneratorKind, Expr, ExprKind, GeneratorKind, GenericBound, HirId, Node, Path, QPath,
+    Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::traits::{self, StatementAsExpression};
@@ -274,13 +275,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) -> bool {
         let expr = expr.peel_blocks();
-        if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
-            self.check_ref(expr, found, expected)
+        if let Some((suggestion, msg, applicability, verbose, annotation)) =
+            self.suggest_deref_or_ref(expr, found, expected)
         {
             if verbose {
-                err.span_suggestion_verbose(sp, msg, suggestion, applicability);
+                err.multipart_suggestion_verbose(msg, suggestion, applicability);
             } else {
-                err.span_suggestion(sp, msg, suggestion, applicability);
+                err.multipart_suggestion(msg, suggestion, applicability);
             }
             if annotation {
                 let suggest_annotation = match expr.peel_drop_temps().kind {
@@ -342,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 err.span_label(sp, format!("{descr} `{name}` defined here"));
             }
             return true;
-        } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+        } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
             return true;
         } else {
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
@@ -438,33 +439,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn suggest_boxing_when_appropriate(
         &self,
         err: &mut Diagnostic,
-        expr: &hir::Expr<'_>,
+        span: Span,
+        hir_id: HirId,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) -> bool {
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return false;
-        }
-        if !expected.is_box() || found.is_box() {
+        // Do not suggest `Box::new` in const context.
+        if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
             return false;
         }
-        let boxed_found = self.tcx.mk_box(found);
-        if self.can_coerce(boxed_found, expected) {
-            err.multipart_suggestion(
-                "store this in the heap by calling `Box::new`",
-                vec![
-                    (expr.span.shrink_to_lo(), "Box::new(".to_string()),
-                    (expr.span.shrink_to_hi(), ")".to_string()),
-                ],
-                Applicability::MachineApplicable,
-            );
-            err.note(
-                "for more on the distinction between the stack and the heap, read \
-                 https://doc.rust-lang.org/book/ch15-01-box.html, \
-                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
-                 https://doc.rust-lang.org/std/boxed/index.html",
-            );
+        if self.can_coerce(self.tcx.mk_box(found), expected) {
+            let suggest_boxing = match found.kind() {
+                ty::Tuple(tuple) if tuple.is_empty() => {
+                    SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
+                }
+                ty::Generator(def_id, ..)
+                    if matches!(
+                        self.tcx.generator_kind(def_id),
+                        Some(GeneratorKind::Async(AsyncGeneratorKind::Closure))
+                    ) =>
+                {
+                    SuggestBoxing::AsyncBody
+                }
+                _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() },
+            };
+            err.subdiagnostic(suggest_boxing);
+
             true
         } else {
             false
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 30f0978d190..486c217707e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1045,7 +1045,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
 
-        self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+        self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
 
         bound_spans.sort();
         bound_spans.dedup();
@@ -1132,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        self.check_for_deref_method(&mut err, source, rcvr_ty, item_name, expected);
+        self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
         return Some(err);
     }
 
@@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_for_inner_self(
+    fn suggest_unwrapping_inner_self(
         &self,
         err: &mut Diagnostic,
         source: SelfSource<'tcx>,
@@ -2175,7 +2175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_for_deref_method(
+    fn note_derefed_ty_has_method(
         &self,
         err: &mut Diagnostic,
         self_source: SelfSource<'tcx>,
@@ -2211,7 +2211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         | ty::Float(_)
                         | ty::Adt(_, _)
                         | ty::Str
-                        | ty::Alias(ty::Projection, _)
+                        | ty::Alias(ty::Projection | ty::Inherent, _)
                         | ty::Param(_) => format!("{deref_ty}"),
                         // we need to test something like  <&[_]>::len or <(&[u32])>::len
                         // and Vec::function();
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 2a51439b0a9..08eec0707c0 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -127,7 +127,8 @@ impl<'tcx> InferCtxt<'tcx> {
                 bug!()
             }
 
-            (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
+            (_, ty::Alias(AliasKind::Projection | AliasKind::Inherent, _))
+            | (ty::Alias(AliasKind::Projection | AliasKind::Inherent, _), _)
                 if self.tcx.trait_solver_next() =>
             {
                 relation.register_type_relate_obligation(a, b);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 98da5ba65b7..ce70f39cc40 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2354,7 +2354,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let labeled_user_string = match bound_kind {
             GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
             GenericKind::Alias(ref p) => match p.kind(self.tcx) {
-                ty::AliasKind::Projection => format!("the associated type `{}`", p),
+                ty::AliasKind::Projection | ty::AliasKind::Inherent => {
+                    format!("the associated type `{}`", p)
+                }
                 ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
             },
         };
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 58e3159a4e2..5000b0139df 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -31,7 +31,7 @@ pub enum TypeAnnotationNeeded {
     /// ```
     E0282,
     /// An implementation cannot be chosen unambiguously because of lack of information.
-    /// ```compile_fail,E0283
+    /// ```compile_fail,E0790
     /// let _ = Default::default();
     /// ```
     E0283,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index da0271a345e..1a60bab18db 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -21,7 +21,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     ///
     /// Consider a case where we have
     ///
-    /// ```compile_fail,E0623
+    /// ```compile_fail
     /// fn foo(x: &mut Vec<&u8>, y: &u8) {
     ///     x.push(y);
     /// }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index fec04af2313..0df417d0950 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Region, TyCtxt};
 /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
 ///
 /// # Example
-/// ```compile_fail,E0623
+/// ```compile_fail
 /// fn foo(x: &mut Vec<&u8>, y: &u8)
 ///    { x.push(y); }
 /// ```
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index a3116351940..064811bd29d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -71,9 +71,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                              #traits-as-parameters",
                         );
                     }
-                    (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
+                    (ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
                         diag.note("an associated type was expected, but a different one was found");
                     }
+                    // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
                     (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
                         if !tcx.is_impl_trait_in_trait(proj.def_id) =>
                     {
@@ -222,7 +223,7 @@ impl<T> Trait<T> for X {
                             diag.span_label(p_span, "this type parameter");
                         }
                     }
-                    (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+                    (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
                         self.expected_projection(
                             diag,
                             proj_ty,
@@ -231,7 +232,7 @@ impl<T> Trait<T> for X {
                             cause.code(),
                         );
                     }
-                    (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+                    (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
                         let msg = format!(
                             "consider constraining the associated type `{}` to `{}`",
                             values.found, values.expected,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 334395945ea..362b22b23a8 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -549,6 +549,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     // We can't normalize associated types from `rustc_infer`,
                     // but we can eagerly register inference variables for them.
                     // FIXME(RPITIT): Don't replace RPITITs with inference vars.
+                    // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
                     ty::Alias(ty::Projection, projection_ty)
                         if !projection_ty.has_escaping_bound_vars()
                             && !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
@@ -569,6 +570,7 @@ impl<'tcx> InferCtxt<'tcx> {
                         hidden_ty
                     }
                     // FIXME(RPITIT): This can go away when we move to associated types
+                    // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
                     ty::Alias(
                         ty::Projection,
                         ty::AliasTy { def_id: def_id2, substs: substs2, .. },
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index 01f900f050e..75ce0f83fd6 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -13,9 +13,11 @@ use crate::infer::region_constraints::VerifyIfEq;
 
 /// Given a "verify-if-eq" type test like:
 ///
-///     exists<'a...> {
-///         verify_if_eq(some_type, bound_region)
-///     }
+/// ```rust,ignore (pseudo-Rust)
+/// exists<'a...> {
+///     verify_if_eq(some_type, bound_region)
+/// }
+/// ```
 ///
 /// and the type `test_ty` that the type test is being tested against,
 /// returns:
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index c86da22526b..c2bf0f3db25 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -277,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     ///
     /// It will not, however, work for higher-ranked bounds like:
     ///
-    /// ```compile_fail,E0311
+    /// ```ignore(this does compile today, previously was marked as `compile_fail,E0311`)
     /// trait Foo<'a, 'b>
     /// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
     /// {
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 6692cd1d389..c7a307b89e4 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -217,7 +217,7 @@ pub enum VerifyBound<'tcx> {
 /// and supplies a bound if it ended up being relevant. It's used in situations
 /// like this:
 ///
-/// ```rust
+/// ```rust,ignore (pseudo-Rust)
 /// fn foo<'a, 'b, T: SomeTrait<'a>>
 /// where
 ///    <T as SomeTrait<'a>>::Item: 'b
@@ -232,7 +232,7 @@ pub enum VerifyBound<'tcx> {
 /// In the [`VerifyBound`], this struct is enclosed in `Binder` to account
 /// for cases like
 ///
-/// ```rust
+/// ```rust,ignore (pseudo-Rust)
 /// where for<'a> <T as SomeTrait<'a>::Item: 'a
 /// ```
 ///
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 0b7a704eb57..3025cce7ba7 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -62,6 +62,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
 use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
@@ -1442,6 +1443,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
             // Bounds are respected for `type X = impl Trait`
             return;
         }
+        if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
+            // Bounds are respected for `type X = … Type::Inherent …`
+            return;
+        }
         // There must not be a where clause
         if type_alias_generics.predicates.is_empty() {
             return;
@@ -1561,7 +1566,6 @@ declare_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        use rustc_middle::ty::visit::TypeVisitableExt;
         use rustc_middle::ty::Clause;
         use rustc_middle::ty::PredicateKind::*;
 
@@ -2898,6 +2902,7 @@ impl ClashingExternDeclarations {
                         | (Generator(..), Generator(..))
                         | (GeneratorWitness(..), GeneratorWitness(..))
                         | (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
+                        | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
                         | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
 
                         // These definitely should have been caught above.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index a6ba742201a..125b4dc5503 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1119,14 +1119,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
             //  so they are currently ignored for the purposes of this lint.
-            ty::Param(..) | ty::Alias(ty::Projection, ..)
+            ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
                 if matches!(self.mode, CItemKind::Definition) =>
             {
                 FfiSafe
             }
 
             ty::Param(..)
-            | ty::Alias(ty::Projection, ..)
+            | ty::Alias(ty::Projection | ty::Inherent, ..)
             | ty::Infer(..)
             | ty::Bound(..)
             | ty::Error(_)
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 6fe15e21d94..6e9dc880a7d 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -333,6 +333,7 @@ declare_lint! {
     ///
     /// ```rust,compile_fail
     /// #![deny(unused_extern_crates)]
+    /// #![deny(warnings)]
     /// extern crate proc_macro;
     /// ```
     ///
@@ -1667,6 +1668,7 @@ declare_lint! {
     ///
     /// ```rust,compile_fail
     /// #![deny(elided_lifetimes_in_paths)]
+    /// #![deny(warnings)]
     /// struct Foo<'a> {
     ///     x: &'a u32
     /// }
@@ -2158,6 +2160,7 @@ declare_lint! {
     /// ```rust,compile_fail
     /// # #![allow(unused)]
     /// #![deny(explicit_outlives_requirements)]
+    /// #![deny(warnings)]
     ///
     /// struct SharedRef<'a, T>
     /// where
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 427c82c410b..cd6e3687460 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -9,7 +9,7 @@ use crate::diagnostics::utils::{
     FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
 use proc_macro2::{Ident, Span, TokenStream};
-use quote::{format_ident, quote};
+use quote::{format_ident, quote, quote_spanned};
 use syn::Token;
 use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
 use synstructure::{BindingInfo, Structure, VariantInfo};
@@ -251,7 +251,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
         let diag = &self.parent.diag;
 
         let field = binding_info.ast();
-        let field_binding = &binding_info.binding;
+        let mut field_binding = binding_info.binding.clone();
+        field_binding.set_span(field.ty.span());
 
         let ident = field.ident.as_ref().unwrap();
         let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
@@ -284,9 +285,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                     name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
                 let (binding, needs_destructure) = if needs_clone {
                     // `primary_span` can accept a `Vec<Span>` so don't destructure that.
-                    (quote! { #field_binding.clone() }, false)
+                    (quote_spanned! {inner_ty.span()=> #field_binding.clone() }, false)
                 } else {
-                    (quote! { #field_binding }, true)
+                    (quote_spanned! {inner_ty.span()=> #field_binding }, true)
                 };
 
                 let generated_code = self
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 62d49c1c64e..374ba1a45c0 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -4,17 +4,16 @@ use crate::diagnostics::error::{
     invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    build_field_mapping, is_doc_comment, new_code_ident,
-    report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
-    FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
+    build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
+    report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
+    should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap,
+    HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
 use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
-use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
-
 /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
 pub(crate) struct SubdiagnosticDeriveBuilder {
     diag: syn::Ident,
@@ -210,19 +209,20 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
     }
 
     /// Generates the code for a field with no attributes.
-    fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
-        let ast = binding.ast();
-        assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
-
+    fn generate_field_set_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
         let diag = &self.parent.diag;
-        let ident = ast.ident.as_ref().unwrap();
-        // strip `r#` prefix, if present
-        let ident = format_ident!("{}", ident);
+
+        let field = binding_info.ast();
+        let mut field_binding = binding_info.binding.clone();
+        field_binding.set_span(field.ty.span());
+
+        let ident = field.ident.as_ref().unwrap();
+        let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
 
         quote! {
             #diag.set_arg(
                 stringify!(#ident),
-                #binding
+                #field_binding
             );
         }
     }
@@ -399,7 +399,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
         clone_suggestion_code: bool,
     ) -> Result<TokenStream, DiagnosticDeriveError> {
         let span = attr.span().unwrap();
-        let ident = &list.path.segments.last().unwrap().ident;
+        let mut ident = list.path.segments.last().unwrap().ident.clone();
+        ident.set_span(info.ty.span());
         let name = ident.to_string();
         let name = name.as_str();
 
@@ -498,7 +499,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
             .variant
             .bindings()
             .iter()
-            .filter(|binding| !binding.ast().attrs.is_empty())
+            .filter(|binding| !should_generate_set_arg(binding.ast()))
             .map(|binding| self.generate_field_attr_code(binding, kind_stats))
             .collect();
 
@@ -580,7 +581,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
             .variant
             .bindings()
             .iter()
-            .filter(|binding| binding.ast().attrs.is_empty())
+            .filter(|binding| should_generate_set_arg(binding.ast()))
             .map(|binding| self.generate_field_set_arg(binding))
             .collect();
 
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index b9b09c66230..e2434981f8d 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -207,6 +207,12 @@ impl<'ty> FieldInnerTy<'ty> {
             FieldInnerTy::Plain(..) => quote! { #inner },
         }
     }
+
+    pub fn span(&self) -> proc_macro2::Span {
+        match self {
+            FieldInnerTy::Option(ty) | FieldInnerTy::Vec(ty) | FieldInnerTy::Plain(ty) => ty.span(),
+        }
+    }
 }
 
 /// Field information passed to the builder. Deliberately omits attrs to discourage the
@@ -851,7 +857,8 @@ impl quote::IdentFragment for SubdiagnosticKind {
 /// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
 /// call (like `span_label`).
 pub(super) fn should_generate_set_arg(field: &Field) -> bool {
-    field.attrs.is_empty()
+    // Perhaps this should be an exhaustive list...
+    field.attrs.iter().all(|attr| is_doc_comment(attr))
 }
 
 pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b425c7600ac..d5b185e45d6 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1821,6 +1821,16 @@ rustc_queries! {
         desc { "normalizing `{}`", goal.value.value }
     }
 
+    /// Do not call this query directly: invoke `normalize` instead.
+    query normalize_inherent_projection_ty(
+        goal: CanonicalProjectionGoal<'tcx>
+    ) -> Result<
+        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
+        NoSolution,
+    > {
+        desc { "normalizing `{}`", goal.value.value }
+    }
+
     /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
     query try_normalize_generic_arg_after_erasing_regions(
         goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 6187fc43cf8..ad9891a5dca 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -26,7 +26,7 @@ use super::{Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, Var
 
 bitflags! {
     #[derive(HashStable, TyEncodable, TyDecodable)]
-    pub struct AdtFlags: u32 {
+    pub struct AdtFlags: u16 {
         const NO_ADT_FLAGS        = 0;
         /// Indicates whether the ADT is an enum.
         const IS_ENUM             = 1 << 0;
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a2e248e45ca..8aea2d8aedf 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1093,11 +1093,13 @@ impl<'tcx> TyCtxt<'tcx> {
         v.0
     }
 
-    /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type and associated alias span when type alias is used
+    /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in
+    /// its return type, and the associated alias span when type alias is used,
+    /// along with a span for lifetime suggestion (if there are existing generics).
     pub fn return_type_impl_or_dyn_traits_with_type_alias(
         self,
         scope_def_id: LocalDefId,
-    ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span)> {
+    ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option<Span>)> {
         let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
         let mut v = TraitObjectVisitor(vec![], self.hir());
         // when the return type is a type alias
@@ -1111,7 +1113,7 @@ impl<'tcx> TyCtxt<'tcx> {
         {
             v.visit_ty(alias_ty);
             if !v.0.is_empty() {
-                return Some((v.0, alias_generics.span));
+                return Some((v.0, alias_generics.span, alias_generics.span_for_lifetime_suggestion()));
             }
         }
         return None;
@@ -1846,7 +1848,17 @@ impl<'tcx> TyCtxt<'tcx> {
         let substs = substs.into_iter().map(Into::into);
         #[cfg(debug_assertions)]
         {
-            let n = self.generics_of(_def_id).count();
+            let generics = self.generics_of(_def_id);
+
+            let n = if let DefKind::AssocTy = self.def_kind(_def_id)
+                && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
+            {
+                // If this is an inherent projection.
+
+                generics.params.len() + 1
+            } else {
+                generics.count()
+            };
             assert_eq!(
                 (n, Some(n)),
                 substs.size_hint(),
@@ -2007,7 +2019,7 @@ impl<'tcx> TyCtxt<'tcx> {
         debug_assert_matches!(
             (kind, self.def_kind(alias_ty.def_id)),
             (ty::Opaque, DefKind::OpaqueTy)
-                | (ty::Projection, DefKind::AssocTy)
+                | (ty::Projection | ty::Inherent, DefKind::AssocTy)
                 | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
         );
         self.mk_ty_from_kind(Alias(kind, alias_ty))
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 1be61e16dbe..49ab9b79e96 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -265,7 +265,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
             ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
             ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
-            ty::Alias(ty::Projection, _) => "associated type".into(),
+            ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
             ty::Param(p) => format!("type parameter `{p}`").into(),
             ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
             ty::Error(_) => "type error".into(),
@@ -312,7 +312,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
             ty::Bound(..) => "bound type variable".into(),
-            ty::Alias(ty::Projection, _) => "associated type".into(),
+            ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
             ty::Param(_) => "type parameter".into(),
             ty::Alias(ty::Opaque, ..) => "opaque type".into(),
         }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 68002bfcfbd..d64875a9f00 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -176,14 +176,14 @@ impl FlagComputation {
                 self.add_substs(substs);
             }
 
-            &ty::Alias(ty::Projection, data) => {
-                self.add_flags(TypeFlags::HAS_TY_PROJECTION);
-                self.add_alias_ty(data);
-            }
+            &ty::Alias(kind, data) => {
+                self.add_flags(match kind {
+                    ty::Projection => TypeFlags::HAS_TY_PROJECTION,
+                    ty::Inherent => TypeFlags::HAS_TY_INHERENT,
+                    ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
+                });
 
-            &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
-                self.add_flags(TypeFlags::HAS_TY_OPAQUE);
-                self.add_substs(substs);
+                self.add_alias_ty(data);
             }
 
             &ty::Dynamic(obj, r, _) => {
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 92a040068dd..9e672004cf9 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -113,6 +113,12 @@ impl<'tcx> Ty<'tcx> {
             }
             Never => InhabitedPredicate::False,
             Param(_) | Alias(ty::Projection, _) => InhabitedPredicate::GenericType(self),
+            // FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above.
+            // However it's unclear if the substs passed to `InhabitedPredicate::subst` are of the correct
+            // format, i.e. don't contain parent substs. If you hit this case, please verify this beforehand.
+            Alias(ty::Inherent, _) => {
+                bug!("unimplemented: inhabitedness checking for inherent projections")
+            }
             Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
             // use a query for more complex cases
             Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 6c8f4af7594..8c69894f5ba 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -115,7 +115,7 @@ impl<'tcx> Instance<'tcx> {
     /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
     pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
         let ty = tcx.type_of(self.def.def_id());
-        tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty.skip_binder())
+        tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty)
     }
 
     /// Finds a crate that contains a monomorphization of this instance that
@@ -578,14 +578,15 @@ impl<'tcx> Instance<'tcx> {
         self.def.has_polymorphic_mir_body().then_some(self.substs)
     }
 
-    pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: &T) -> T
+    pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>> + Copy,
     {
+        let v = v.map_bound(|v| *v);
         if let Some(substs) = self.substs_for_mir_body() {
-            EarlyBinder(*v).subst(tcx, substs)
+            v.subst(tcx, substs)
         } else {
-            *v
+            v.skip_binder()
         }
     }
 
@@ -594,7 +595,7 @@ impl<'tcx> Instance<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        v: T,
+        v: EarlyBinder<T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>> + Clone,
@@ -602,7 +603,7 @@ impl<'tcx> Instance<'tcx> {
         if let Some(substs) = self.substs_for_mir_body() {
             tcx.subst_and_normalize_erasing_regions(substs, param_env, v)
         } else {
-            tcx.normalize_erasing_regions(param_env, v)
+            tcx.normalize_erasing_regions(param_env, v.skip_binder())
         }
     }
 
@@ -611,7 +612,7 @@ impl<'tcx> Instance<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        v: T,
+        v: EarlyBinder<T>,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>> + Clone,
@@ -619,7 +620,7 @@ impl<'tcx> Instance<'tcx> {
         if let Some(substs) = self.substs_for_mir_body() {
             tcx.try_subst_and_normalize_erasing_regions(substs, param_env, v)
         } else {
-            tcx.try_normalize_erasing_regions(param_env, v)
+            tcx.try_normalize_erasing_regions(param_env, v.skip_binder())
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f2a2e67cf82..47cf48f46cf 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -324,7 +324,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
                 let non_zero = !ty.is_unsafe_ptr();
                 let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
                 match tail.kind() {
-                    ty::Param(_) | ty::Alias(ty::Projection, _) => {
+                    ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
                         debug_assert!(tail.has_non_region_param());
                         Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
                     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 23d6242899f..f882f54d628 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1004,7 +1004,7 @@ impl<'tcx> Term<'tcx> {
         match self.unpack() {
             TermKind::Ty(ty) => match ty.kind() {
                 ty::Alias(kind, alias_ty) => match kind {
-                    AliasKind::Projection => Some(*alias_ty),
+                    AliasKind::Projection | AliasKind::Inherent => Some(*alias_ty),
                     AliasKind::Opaque => None,
                 },
                 _ => None,
@@ -1739,7 +1739,7 @@ pub struct Destructor {
 
 bitflags! {
     #[derive(HashStable, TyEncodable, TyDecodable)]
-    pub struct VariantFlags: u32 {
+    pub struct VariantFlags: u8 {
         const NO_VARIANT_FLAGS        = 0;
         /// Indicates whether the field list of this variant is `#[non_exhaustive]`.
         const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0;
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 7c59879a187..9332b0430ff 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -139,7 +139,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         param_substs: SubstsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: T,
+        value: EarlyBinder<T>,
     ) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -151,7 +151,7 @@ impl<'tcx> TyCtxt<'tcx> {
              param_env={:?})",
             param_substs, value, param_env,
         );
-        let substituted = EarlyBinder(value).subst(self, param_substs);
+        let substituted = value.subst(self, param_substs);
         self.normalize_erasing_regions(param_env, substituted)
     }
 
@@ -163,7 +163,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self,
         param_substs: SubstsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: T,
+        value: EarlyBinder<T>,
     ) -> Result<T, NormalizationError<'tcx>>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
@@ -175,7 +175,7 @@ impl<'tcx> TyCtxt<'tcx> {
              param_env={:?})",
             param_substs, value, param_env,
         );
-        let substituted = EarlyBinder(value).subst(self, param_substs);
+        let substituted = value.subst(self, param_substs);
         self.try_normalize_erasing_regions(param_env, substituted)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index b7e780b94ef..926172ff828 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -729,7 +729,7 @@ pub trait PrettyPrinter<'tcx>:
             ty::Foreign(def_id) => {
                 p!(print_def_path(def_id, &[]));
             }
-            ty::Alias(ty::Projection, ref data) => {
+            ty::Alias(ty::Projection | ty::Inherent, ref data) => {
                 if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
                     && self.tcx().is_impl_trait_in_trait(data.def_id)
                 {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 7f28ed6c263..da43475941e 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -550,6 +550,11 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
         }
 
+        (&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => {
+            let alias_ty = relation.relate(a_data, b_data)?;
+            Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs)))
+        }
+
         (
             &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
             &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 646384eebc8..8d0737e1eee 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1190,9 +1190,9 @@ where
 
 /// Represents the projection of an associated type.
 ///
-/// For a projection, this would be `<Ty as Trait<...>>::N`.
-///
-/// For an opaque type, there is no explicit syntax.
+/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
+/// * For an inherent projection, this would be `Ty::N<...>`.
+/// * For an opaque type, there is no explicit syntax.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct AliasTy<'tcx> {
@@ -1201,12 +1201,16 @@ pub struct AliasTy<'tcx> {
     /// For a projection, these are the substitutions for the trait and the
     /// GAT substitutions, if there are any.
     ///
+    /// For an inherent projection, they consist of the self type and the GAT substitutions,
+    /// if there are any.
+    ///
     /// For RPIT the substitutions are for the generics of the function,
     /// while for TAIT it is used for the generic parameters of the alias.
     pub substs: SubstsRef<'tcx>,
 
-    /// The `DefId` of the `TraitItem` for the associated type `N` if this is a projection,
-    /// or the `OpaqueType` item if this is an opaque.
+    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
+    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
+    /// this is an opaque.
     ///
     /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
     /// underlying type if the type is an opaque.
@@ -1224,6 +1228,7 @@ pub struct AliasTy<'tcx> {
 impl<'tcx> AliasTy<'tcx> {
     pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
         match tcx.def_kind(self.def_id) {
+            DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
             DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
             DefKind::OpaqueTy => ty::Opaque,
             kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
@@ -1237,6 +1242,17 @@ impl<'tcx> AliasTy<'tcx> {
 
 /// The following methods work only with associated type projections.
 impl<'tcx> AliasTy<'tcx> {
+    pub fn self_ty(self) -> Ty<'tcx> {
+        self.substs.type_at(0)
+    }
+
+    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+        tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
+    }
+}
+
+/// The following methods work only with trait associated type projections.
+impl<'tcx> AliasTy<'tcx> {
     pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
         match tcx.def_kind(self.def_id) {
             DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
@@ -1274,13 +1290,28 @@ impl<'tcx> AliasTy<'tcx> {
         let def_id = self.trait_def_id(tcx);
         ty::TraitRef::new(tcx, def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
     }
+}
 
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.substs.type_at(0)
-    }
+/// The following methods work only with inherent associated type projections.
+impl<'tcx> AliasTy<'tcx> {
+    /// Transform the substitutions to have the given `impl` substs as the base and the GAT substs on top of that.
+    ///
+    /// Does the following transformation:
+    ///
+    /// ```text
+    /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
+    ///
+    ///     I_i impl subst
+    ///     P_j GAT subst
+    /// ```
+    pub fn rebase_substs_onto_impl(
+        self,
+        impl_substs: ty::SubstsRef<'tcx>,
+        tcx: TyCtxt<'tcx>,
+    ) -> ty::SubstsRef<'tcx> {
+        debug_assert_eq!(self.kind(tcx), ty::Inherent);
 
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
+        tcx.mk_substs_from_iter(impl_substs.into_iter().chain(self.substs.into_iter().skip(1)))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 5eaa58d69ed..520bb55e031 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -49,6 +49,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
     fn has_projections(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_PROJECTION)
     }
+    fn has_inherent_projections(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
+    }
     fn has_opaque_types(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
     }
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 962536669e0..eca5f98a2c0 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -24,6 +24,8 @@ rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_span = { path = "../rustc_span" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_macros = { path = "../rustc_macros" }
 
 [dev-dependencies]
 coverage_test_macros = { path = "src/coverage/test_macros" }
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
new file mode 100644
index 00000000000..8c85cb5f76d
--- /dev/null
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -0,0 +1,66 @@
+mir_transform_const_modify = attempting to modify a `const` item
+    .note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified
+
+mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
+    .note = each usage of a `const` item creates a new temporary
+    .note2 = the mutable reference will refer to this temporary, not the original `const` item
+    .note3 = mutable reference created due to call to this method
+
+mir_transform_const_defined_here = `const` item defined here
+
+mir_transform_unaligned_packed_ref = reference to packed field is unaligned
+    .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+    .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+    .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+mir_transform_unused_unsafe = unnecessary `unsafe` block
+    .label = because it's nested under this `unsafe` block
+
+mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
+    [true] function or block
+    *[false] block
+    }
+    .not_inherited = items do not inherit unsafety from separate enclosing items
+
+mir_transform_call_to_unsafe_label = call to unsafe function
+mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
+mir_transform_use_of_asm_label = use of inline assembly
+mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
+mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+mir_transform_const_ptr2int_label = cast of pointer to int
+mir_transform_const_ptr2int_note = casting pointers to integers in constants
+mir_transform_use_of_static_mut_label = use of mutable static
+mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+mir_transform_use_of_extern_static_label = use of extern static
+mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+mir_transform_deref_ptr_label = dereference of raw pointer
+mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+mir_transform_union_access_label = access to union field
+mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
+mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
+mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
+mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+mir_transform_target_feature_call_label = call to function with `#[target_feature]`
+mir_transform_target_feature_call_note = can only be called if the required target features are available
+
+mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
+
+mir_transform_arithmetic_overflow = this arithmetic operation will overflow
+mir_transform_operation_will_panic = this operation will panic at runtime
+
+mir_transform_ffi_unwind_call = call to {$foreign ->
+    [true] foreign function
+    *[false] function pointer
+    } with FFI-unwind ABI
+
+mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
+    .suggestion = cast `{$ident}` to obtain a function pointer
+
+mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
+    .label = the value is held across this suspend point
+    .note = {$reason}
+    .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
+
+mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 57b24c9c552..b79150737d6 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -1,11 +1,12 @@
-use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
+use rustc_hir::HirId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
 use rustc_span::def_id::DefId;
+use rustc_span::Span;
 
-use crate::MirLint;
+use crate::{errors, MirLint};
 
 pub struct CheckConstItemMutation;
 
@@ -58,16 +59,14 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
         }
     }
 
-    fn lint_const_item_usage(
+    /// If we should lint on this usage, return the [`HirId`], source [`Span`]
+    /// and [`Span`] of the const item to use in the lint.
+    fn should_lint_const_item_usage(
         &self,
         place: &Place<'tcx>,
         const_item: DefId,
         location: Location,
-        msg: impl Into<DiagnosticMessage>,
-        decorate: impl for<'a, 'b> FnOnce(
-            &'a mut DiagnosticBuilder<'b, ()>,
-        ) -> &'a mut DiagnosticBuilder<'b, ()>,
-    ) {
+    ) -> Option<(HirId, Span, Span)> {
         // Don't lint on borrowing/assigning when a dereference is involved.
         // If we 'leave' the temporary via a dereference, we must
         // be modifying something else
@@ -83,16 +82,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
                 .assert_crate_local()
                 .lint_root;
 
-            self.tcx.struct_span_lint_hir(
-                CONST_ITEM_MUTATION,
-                lint_root,
-                source_info.span,
-                msg,
-                |lint| {
-                    decorate(lint)
-                        .span_note(self.tcx.def_span(const_item), "`const` item defined here")
-                },
-            );
+            Some((lint_root, source_info.span, self.tcx.def_span(const_item)))
+        } else {
+            None
         }
     }
 }
@@ -104,10 +96,14 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
             // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
             // so emitting a lint would be redundant.
             if !lhs.projection.is_empty() {
-                if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
-                    self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
-                        lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
-                    })
+                if let Some(def_id) = self.is_const_item_without_destructor(lhs.local)
+                    && let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) {
+                        self.tcx.emit_spanned_lint(
+                            CONST_ITEM_MUTATION,
+                            lint_root,
+                            span,
+                            errors::ConstMutate::Modify { konst: item }
+                        );
                 }
             }
             // We are looking for MIR of the form:
@@ -143,17 +139,22 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
                 });
                 let lint_loc =
                     if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
-                self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
-                    lint
-                        .note("each usage of a `const` item creates a new temporary")
-                        .note("the mutable reference will refer to this temporary, not the original `const` item");
-
-                    if let Some((method_did, _substs)) = method_did {
-                        lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
-                    }
 
-                    lint
-                });
+                let method_call = if let Some((method_did, _)) = method_did {
+                    Some(self.tcx.def_span(method_did))
+                } else {
+                    None
+                };
+                if let Some((lint_root, span, item)) =
+                    self.should_lint_const_item_usage(place, def_id, lint_loc)
+                {
+                    self.tcx.emit_spanned_lint(
+                        CONST_ITEM_MUTATION,
+                        lint_root,
+                        span,
+                        errors::ConstMutate::MutBorrow { method_call, konst: item },
+                    );
+                }
             }
         }
         self.super_rvalue(rvalue, loc);
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index b9bc89fcf8f..2e6cf603d59 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -1,10 +1,9 @@
-use rustc_errors::struct_span_err;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
 
-use crate::util;
 use crate::MirLint;
+use crate::{errors, util};
 
 pub struct CheckPackedRef;
 
@@ -49,25 +48,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
                     // shouldn't do.
                     span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
                 } else {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        self.source_info.span,
-                        E0793,
-                        "reference to packed field is unaligned"
-                    )
-                    .note(
-                        "packed structs are only aligned by one byte, and many modern architectures \
-                        penalize unaligned field accesses"
-                    )
-                    .note(
-                        "creating a misaligned reference is undefined behavior (even if that \
-                        reference is never dereferenced)",
-                    ).help(
-                        "copy the field contents to a local variable, or replace the \
-                        reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
-                        (loads and stores via `*p` must be properly aligned even when using raw pointers)"
-                    )
-                    .emit();
+                    self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
                 }
             }
         }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index ce6d865a7dc..bdb4f20da10 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -1,5 +1,4 @@
 use rustc_data_structures::unord::{UnordItems, UnordSet};
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +14,8 @@ use rustc_session::lint::Level;
 
 use std::ops::Bound;
 
+use crate::errors;
+
 pub struct UnsafetyChecker<'a, 'tcx> {
     body: &'a Body<'tcx>,
     body_did: LocalDefId,
@@ -509,21 +510,12 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu
 
 fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
     let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
-    let msg = "unnecessary `unsafe` block";
-    tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
-        lint.span_label(span, msg);
-        match kind {
-            UnusedUnsafe::Unused => {}
-            UnusedUnsafe::InUnsafeBlock(id) => {
-                lint.span_label(
-                    tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
-                    "because it's nested under this `unsafe` block",
-                );
-            }
-        }
-
-        lint
-    });
+    let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
+        Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
+    } else {
+        None
+    };
+    tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
 }
 
 pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@@ -537,26 +529,11 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
 
     for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
-        let (description, note) = details.description_and_note();
+        let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
 
         match kind {
             UnsafetyViolationKind::General => {
-                // once
-                let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
-                    " function or"
-                } else {
-                    ""
-                };
-
-                let mut err = struct_span_err!(
-                    tcx.sess,
-                    source_info.span,
-                    E0133,
-                    "{} is unsafe and requires unsafe{} block",
-                    description,
-                    unsafe_fn_msg,
-                );
-                err.span_label(source_info.span, description).note(note);
+                let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
                 let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
                     if let Node::Expr(block) = node
                         && let ExprKind::Block(block, _) = block.kind
@@ -572,22 +549,23 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                         false
                     }
                 });
-                if let Some((id, _)) = note_non_inherited {
-                    let span = tcx.hir().span(id);
-                    err.span_label(
-                        tcx.sess.source_map().guess_head_span(span),
-                        "items do not inherit unsafety from separate enclosing items",
-                    );
-                }
-
-                err.emit();
+                let enclosing = if let Some((id, _)) = note_non_inherited {
+                    Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
+                } else {
+                    None
+                };
+                tcx.sess.emit_err(errors::RequiresUnsafe {
+                    span: source_info.span,
+                    enclosing,
+                    details,
+                    op_in_unsafe_fn_allowed,
+                });
             }
-            UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
+            UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 lint_root,
                 source_info.span,
-                format!("{} is unsafe and requires unsafe block (error E0133)", description,),
-                |lint| lint.span_label(source_info.span, description).note(note),
+                errors::UnsafeOpInUnsafeFn { details },
             ),
         }
     }
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 7f995c69a48..a5d18fff89b 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -806,6 +806,24 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
         }
     }
 
+    fn process_projection_elem(
+        &mut self,
+        elem: PlaceElem<'tcx>,
+        _: Location,
+    ) -> Option<PlaceElem<'tcx>> {
+        if let PlaceElem::Index(local) = elem
+            && let Some(value) = self.get_const(local.into())
+            && self.should_const_prop(&value)
+            && let interpret::Operand::Immediate(interpret::Immediate::Scalar(scalar)) = *value
+            && let Ok(offset) = scalar.to_target_usize(&self.tcx)
+            && let Some(min_length) = offset.checked_add(1)
+        {
+            Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
+        } else {
+            None
+        }
+    }
+
     fn visit_assign(
         &mut self,
         place: &mut Place<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index a4049d08d7b..adb09c509d2 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -1,6 +1,8 @@
 //! Propagates constants for early reporting of statically known
 //! assertion failures
 
+use std::fmt::Debug;
+
 use either::Left;
 
 use rustc_const_eval::interpret::Immediate;
@@ -17,7 +19,6 @@ use rustc_middle::ty::InternalSubsts;
 use rustc_middle::ty::{
     self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
 };
-use rustc_session::lint;
 use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
 use rustc_trait_selection::traits;
@@ -25,6 +26,7 @@ use rustc_trait_selection::traits;
 use crate::const_prop::CanConstProp;
 use crate::const_prop::ConstPropMachine;
 use crate::const_prop::ConstPropMode;
+use crate::errors::AssertLint;
 use crate::MirLint;
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -311,18 +313,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn report_assert_as_lint(
-        &self,
-        lint: &'static lint::Lint,
-        location: Location,
-        message: &'static str,
-        panic: AssertKind<impl std::fmt::Debug>,
-    ) {
-        let source_info = self.body().source_info(location);
+    fn report_assert_as_lint(&self, source_info: &SourceInfo, lint: AssertLint<impl Debug>) {
         if let Some(lint_root) = self.lint_root(*source_info) {
-            self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
-                lint.span_label(source_info.span, format!("{:?}", panic))
-            });
+            self.tcx.emit_spanned_lint(lint.lint(), lint_root, source_info.span, lint);
         }
     }
 
@@ -335,11 +328,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
             // appropriate to use.
             assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
+            let source_info = self.body().source_info(location);
             self.report_assert_as_lint(
-                lint::builtin::ARITHMETIC_OVERFLOW,
-                location,
-                "this arithmetic operation will overflow",
-                AssertKind::OverflowNeg(val.to_const_int()),
+                source_info,
+                AssertLint::ArithmeticOverflow(
+                    source_info.span,
+                    AssertKind::OverflowNeg(val.to_const_int()),
+                ),
             );
             return None;
         }
@@ -370,23 +365,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             let r_bits = r.to_scalar().to_bits(right_size).ok();
             if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
                 debug!("check_binary_op: reporting assert for {:?}", location);
+                let source_info = self.body().source_info(location);
+                let panic = AssertKind::Overflow(
+                    op,
+                    match l {
+                        Some(l) => l.to_const_int(),
+                        // Invent a dummy value, the diagnostic ignores it anyway
+                        None => ConstInt::new(
+                            ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
+                            left_ty.is_signed(),
+                            left_ty.is_ptr_sized_integral(),
+                        ),
+                    },
+                    r.to_const_int(),
+                );
                 self.report_assert_as_lint(
-                    lint::builtin::ARITHMETIC_OVERFLOW,
-                    location,
-                    "this arithmetic operation will overflow",
-                    AssertKind::Overflow(
-                        op,
-                        match l {
-                            Some(l) => l.to_const_int(),
-                            // Invent a dummy value, the diagnostic ignores it anyway
-                            None => ConstInt::new(
-                                ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
-                                left_ty.is_signed(),
-                                left_ty.is_ptr_sized_integral(),
-                            ),
-                        },
-                        r.to_const_int(),
-                    ),
+                    source_info,
+                    AssertLint::ArithmeticOverflow(source_info.span, panic),
                 );
                 return None;
             }
@@ -398,11 +393,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
                 Ok(overflow)
             })? {
+                let source_info = self.body().source_info(location);
                 self.report_assert_as_lint(
-                    lint::builtin::ARITHMETIC_OVERFLOW,
-                    location,
-                    "this arithmetic operation will overflow",
-                    AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
+                    source_info,
+                    AssertLint::ArithmeticOverflow(
+                        source_info.span,
+                        AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
+                    ),
                 );
                 return None;
             }
@@ -543,11 +540,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 // Need proper const propagator for these.
                 _ => return None,
             };
+            let source_info = self.body().source_info(location);
             self.report_assert_as_lint(
-                lint::builtin::UNCONDITIONAL_PANIC,
-                location,
-                "this operation will panic at runtime",
-                msg,
+                source_info,
+                AssertLint::UnconditionalPanic(source_info.span, msg),
             );
         }
 
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
new file mode 100644
index 00000000000..602e40d5131
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -0,0 +1,245 @@
+use rustc_errors::{
+    DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, IntoDiagnostic,
+};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
+use rustc_session::lint::{self, Lint};
+use rustc_span::Span;
+
+#[derive(LintDiagnostic)]
+pub(crate) enum ConstMutate {
+    #[diag(mir_transform_const_modify)]
+    #[note]
+    Modify {
+        #[note(mir_transform_const_defined_here)]
+        konst: Span,
+    },
+    #[diag(mir_transform_const_mut_borrow)]
+    #[note]
+    #[note(mir_transform_note2)]
+    MutBorrow {
+        #[note(mir_transform_note3)]
+        method_call: Option<Span>,
+        #[note(mir_transform_const_defined_here)]
+        konst: Span,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_transform_unaligned_packed_ref, code = "E0793")]
+#[note]
+#[note(mir_transform_note_ub)]
+#[help]
+pub(crate) struct UnalignedPackedRef {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_unused_unsafe)]
+pub(crate) struct UnusedUnsafe {
+    #[label(mir_transform_unused_unsafe)]
+    pub span: Span,
+    #[label]
+    pub nested_parent: Option<Span>,
+}
+
+pub(crate) struct RequiresUnsafe {
+    pub span: Span,
+    pub details: RequiresUnsafeDetail,
+    pub enclosing: Option<Span>,
+    pub op_in_unsafe_fn_allowed: bool,
+}
+
+// The primary message for this diagnostic should be '{$label} is unsafe and...',
+// so we need to eagerly translate the label here, which isn't supported by the derive API
+// We could also exhaustively list out the primary messages for all unsafe violations,
+// but this would result in a lot of duplication.
+impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
+    #[track_caller]
+    fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> {
+        let mut diag =
+            handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe);
+        diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
+        diag.set_span(self.span);
+        diag.span_label(self.span, self.details.label());
+        diag.note(self.details.note());
+        let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
+        diag.set_arg("details", desc);
+        diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
+        if let Some(sp) = self.enclosing {
+            diag.span_label(sp, crate::fluent_generated::mir_transform_not_inherited);
+        }
+        diag
+    }
+}
+
+#[derive(Copy, Clone)]
+pub(crate) struct RequiresUnsafeDetail {
+    pub span: Span,
+    pub violation: UnsafetyViolationDetails,
+}
+
+impl RequiresUnsafeDetail {
+    fn note(self) -> DiagnosticMessage {
+        use UnsafetyViolationDetails::*;
+        match self.violation {
+            CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_note,
+            UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_note,
+            InitializingTypeWith => {
+                crate::fluent_generated::mir_transform_initializing_valid_range_note
+            }
+            CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_note,
+            UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_note,
+            UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_note,
+            DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_note,
+            AccessToUnionField => crate::fluent_generated::mir_transform_union_access_note,
+            MutationOfLayoutConstrainedField => {
+                crate::fluent_generated::mir_transform_mutation_layout_constrained_note
+            }
+            BorrowOfLayoutConstrainedField => {
+                crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note
+            }
+            CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note,
+        }
+    }
+
+    fn label(self) -> DiagnosticMessage {
+        use UnsafetyViolationDetails::*;
+        match self.violation {
+            CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_label,
+            UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_label,
+            InitializingTypeWith => {
+                crate::fluent_generated::mir_transform_initializing_valid_range_label
+            }
+            CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_label,
+            UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_label,
+            UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_label,
+            DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_label,
+            AccessToUnionField => crate::fluent_generated::mir_transform_union_access_label,
+            MutationOfLayoutConstrainedField => {
+                crate::fluent_generated::mir_transform_mutation_layout_constrained_label
+            }
+            BorrowOfLayoutConstrainedField => {
+                crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label
+            }
+            CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label,
+        }
+    }
+}
+
+pub(crate) struct UnsafeOpInUnsafeFn {
+    pub details: RequiresUnsafeDetail,
+}
+
+impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
+    #[track_caller]
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut DiagnosticBuilder<'a, ()> {
+        let desc = diag
+            .handler()
+            .expect("lint should not yet be emitted")
+            .eagerly_translate_to_string(self.details.label(), [].into_iter());
+        diag.set_arg("details", desc);
+        diag.span_label(self.details.span, self.details.label());
+        diag.note(self.details.note());
+        diag
+    }
+
+    fn msg(&self) -> DiagnosticMessage {
+        crate::fluent_generated::mir_transform_unsafe_op_in_unsafe_fn
+    }
+}
+
+pub(crate) enum AssertLint<P> {
+    ArithmeticOverflow(Span, AssertKind<P>),
+    UnconditionalPanic(Span, AssertKind<P>),
+}
+
+impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> {
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut DiagnosticBuilder<'a, ()> {
+        diag.span_label(self.span(), format!("{:?}", self.panic()));
+        diag
+    }
+
+    fn msg(&self) -> DiagnosticMessage {
+        match self {
+            AssertLint::ArithmeticOverflow(..) => {
+                crate::fluent_generated::mir_transform_arithmetic_overflow
+            }
+            AssertLint::UnconditionalPanic(..) => {
+                crate::fluent_generated::mir_transform_operation_will_panic
+            }
+        }
+    }
+}
+
+impl<P> AssertLint<P> {
+    pub fn lint(&self) -> &'static Lint {
+        match self {
+            AssertLint::ArithmeticOverflow(..) => lint::builtin::ARITHMETIC_OVERFLOW,
+            AssertLint::UnconditionalPanic(..) => lint::builtin::UNCONDITIONAL_PANIC,
+        }
+    }
+    pub fn span(&self) -> Span {
+        match self {
+            AssertLint::ArithmeticOverflow(sp, _) | AssertLint::UnconditionalPanic(sp, _) => *sp,
+        }
+    }
+    pub fn panic(&self) -> &AssertKind<P> {
+        match self {
+            AssertLint::ArithmeticOverflow(_, p) | AssertLint::UnconditionalPanic(_, p) => p,
+        }
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_ffi_unwind_call)]
+pub(crate) struct FfiUnwindCall {
+    #[label(mir_transform_ffi_unwind_call)]
+    pub span: Span,
+    pub foreign: bool,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_fn_item_ref)]
+pub(crate) struct FnItemRef {
+    #[suggestion(code = "{sugg}", applicability = "unspecified")]
+    pub span: Span,
+    pub sugg: String,
+    pub ident: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_must_not_suspend)]
+pub(crate) struct MustNotSupend<'a> {
+    #[label]
+    pub yield_sp: Span,
+    #[subdiagnostic]
+    pub reason: Option<MustNotSuspendReason>,
+    #[help]
+    pub src_sp: Span,
+    pub pre: &'a str,
+    pub def_path: String,
+    pub post: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[note(mir_transform_note)]
+pub(crate) struct MustNotSuspendReason {
+    #[primary_span]
+    pub span: Span,
+    pub reason: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_transform_simd_shuffle_last_const)]
+pub(crate) struct SimdShuffleLastConst {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index db68adc8bc9..ac1de989a72 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -8,6 +8,8 @@ use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
 use rustc_target::spec::abi::Abi;
 use rustc_target::spec::PanicStrategy;
 
+use crate::errors;
+
 fn abi_can_unwind(abi: Abi) -> bool {
     use Abi::*;
     match abi {
@@ -107,13 +109,13 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
                 .lint_root;
             let span = terminator.source_info.span;
 
-            let msg = match fn_def_id {
-                Some(_) => "call to foreign function with FFI-unwind ABI",
-                None => "call to function pointer with FFI-unwind ABI",
-            };
-            tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
-                lint.span_label(span, msg)
-            });
+            let foreign = fn_def_id.is_some();
+            tcx.emit_spanned_lint(
+                FFI_UNWIND_CALLS,
+                lint_root,
+                span,
+                errors::FfiUnwindCall { span, foreign },
+            );
 
             tainted = true;
         }
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index f26c6de9648..5989dbebf2d 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -1,5 +1,4 @@
 use itertools::Itertools;
-use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
@@ -8,7 +7,7 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
 
-use crate::MirLint;
+use crate::{errors, MirLint};
 
 pub struct FunctionItemReferences;
 
@@ -174,27 +173,21 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
         let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
         let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
         let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
-        self.tcx.struct_span_lint_hir(
+        let sugg = format!(
+            "{} as {}{}fn({}{}){}",
+            if params.is_empty() { ident.clone() } else { format!("{}::<{}>", ident, params) },
+            unsafety,
+            abi,
+            vec!["_"; num_args].join(", "),
+            variadic,
+            ret,
+        );
+
+        self.tcx.emit_spanned_lint(
             FUNCTION_ITEM_REFERENCES,
             lint_root,
             span,
-            "taking a reference to a function item does not give a function pointer",
-            |lint| {
-                lint.span_suggestion(
-                    span,
-                    format!("cast `{}` to obtain a function pointer", ident),
-                    format!(
-                        "{} as {}{}fn({}{}){}",
-                        if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
-                        unsafety,
-                        abi,
-                        vec!["_"; num_args].join(", "),
-                        variadic,
-                        ret,
-                    ),
-                    Applicability::Unspecified,
-                )
-            },
+            errors::FnItemRef { span, sugg, ident },
         );
     }
 }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 9e16c400f14..c9144729145 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -51,6 +51,7 @@
 //! Otherwise it drops all the values in scope at the last suspension point.
 
 use crate::deref_separator::deref_finder;
+use crate::errors;
 use crate::simplify;
 use crate::MirPass;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -1891,36 +1892,21 @@ fn check_must_not_suspend_def(
     data: SuspendCheckData<'_>,
 ) -> bool {
     if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
-        let msg = rustc_errors::DelayDm(|| {
-            format!(
-                "{}`{}`{} held across a suspend point, but should not be",
-                data.descr_pre,
-                tcx.def_path_str(def_id),
-                data.descr_post,
-            )
+        let reason = attr.value_str().map(|s| errors::MustNotSuspendReason {
+            span: data.source_span,
+            reason: s.as_str().to_string(),
         });
-        tcx.struct_span_lint_hir(
+        tcx.emit_spanned_lint(
             rustc_session::lint::builtin::MUST_NOT_SUSPEND,
             hir_id,
             data.source_span,
-            msg,
-            |lint| {
-                // add span pointing to the offending yield/await
-                lint.span_label(data.yield_span, "the value is held across this suspend point");
-
-                // Add optional reason note
-                if let Some(note) = attr.value_str() {
-                    // FIXME(guswynn): consider formatting this better
-                    lint.span_note(data.source_span, note.as_str());
-                }
-
-                // Add some quick suggestions on what to do
-                // FIXME: can `drop` work as a suggestion here as well?
-                lint.span_help(
-                    data.source_span,
-                    "consider using a block (`{ ... }`) \
-                    to shrink the value's scope, ending before the suspend point",
-                )
+            errors::MustNotSupend {
+                yield_sp: data.yield_span,
+                reason,
+                src_sp: data.source_span,
+                pre: data.descr_pre,
+                def_path: tcx.def_path_str(def_id),
+                post: data.descr_post,
             },
         );
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 71bdfd5aae1..ece20d8d3e6 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -180,7 +180,7 @@ impl<'tcx> Inliner<'tcx> {
         let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
             self.tcx,
             self.param_env,
-            callee_body.clone(),
+            ty::EarlyBinder(callee_body.clone()),
         ) else {
             return Err("failed to normalize callee body");
         };
@@ -444,7 +444,9 @@ impl<'tcx> Inliner<'tcx> {
                 work_list.push(target);
 
                 // If the place doesn't actually need dropping, treat it like a regular goto.
-                let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
+                let ty = callsite
+                    .callee
+                    .subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty));
                 if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
                         work_list.push(unwind);
                     }
@@ -788,7 +790,9 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
         match terminator.kind {
             TerminatorKind::Drop { ref place, unwind, .. } => {
                 // If the place doesn't actually need dropping, treat it like a regular goto.
-                let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
+                let ty = self
+                    .instance
+                    .subst_mir(tcx, ty::EarlyBinder(&place.ty(self.callee_body, tcx).ty));
                 if ty.needs_drop(tcx, self.param_env) {
                     self.cost += CALL_PENALTY;
                     if let UnwindAction::Cleanup(_) = unwind {
@@ -799,7 +803,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
                 }
             }
             TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
-                let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty());
+                let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder(&f.literal.ty()));
                 self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
                     // Don't give intrinsics the extra penalty for calls
                     INSTR_COST
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 6046c3876be..1ccf06f6153 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -44,7 +44,11 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
     ) -> bool {
         trace!(%caller);
         for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
-            let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(tcx, param_env, substs) else {
+            let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(
+                tcx,
+                param_env,
+                ty::EarlyBinder(substs),
+            ) else {
                 trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping");
                 continue;
             };
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 432852a1fdd..6bff535586a 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -1,6 +1,6 @@
 //! Performs various peephole optimizations.
 
-use crate::simplify::combine_duplicate_switch_targets;
+use crate::simplify::simplify_duplicate_switch_targets;
 use crate::MirPass;
 use rustc_hir::Mutability;
 use rustc_middle::mir::*;
@@ -10,15 +10,15 @@ use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::FieldIdx;
 
-pub struct InstCombine;
+pub struct InstSimplify;
 
-impl<'tcx> MirPass<'tcx> for InstCombine {
+impl<'tcx> MirPass<'tcx> for InstSimplify {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let ctx = InstCombineContext {
+        let ctx = InstSimplifyContext {
             tcx,
             local_decls: &body.local_decls,
             param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
@@ -27,43 +27,43 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
             for statement in block.statements.iter_mut() {
                 match statement.kind {
                     StatementKind::Assign(box (_place, ref mut rvalue)) => {
-                        ctx.combine_bool_cmp(&statement.source_info, rvalue);
-                        ctx.combine_ref_deref(&statement.source_info, rvalue);
-                        ctx.combine_len(&statement.source_info, rvalue);
-                        ctx.combine_cast(&statement.source_info, rvalue);
+                        ctx.simplify_bool_cmp(&statement.source_info, rvalue);
+                        ctx.simplify_ref_deref(&statement.source_info, rvalue);
+                        ctx.simplify_len(&statement.source_info, rvalue);
+                        ctx.simplify_cast(&statement.source_info, rvalue);
                     }
                     _ => {}
                 }
             }
 
-            ctx.combine_primitive_clone(
+            ctx.simplify_primitive_clone(
                 &mut block.terminator.as_mut().unwrap(),
                 &mut block.statements,
             );
-            ctx.combine_intrinsic_assert(
+            ctx.simplify_intrinsic_assert(
                 &mut block.terminator.as_mut().unwrap(),
                 &mut block.statements,
             );
-            combine_duplicate_switch_targets(block.terminator.as_mut().unwrap());
+            simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
         }
     }
 }
 
-struct InstCombineContext<'tcx, 'a> {
+struct InstSimplifyContext<'tcx, 'a> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
     param_env: ParamEnv<'tcx>,
 }
 
-impl<'tcx> InstCombineContext<'tcx, '_> {
-    fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
+impl<'tcx> InstSimplifyContext<'tcx, '_> {
+    fn should_simplify(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
         self.tcx.consider_optimizing(|| {
-            format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
+            format!("InstSimplify - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
         })
     }
 
     /// Transform boolean comparisons into logical operations.
-    fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+    fn simplify_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
         match rvalue {
             Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => {
                 let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
@@ -94,7 +94,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
                     _ => None,
                 };
 
-                if let Some(new) = new && self.should_combine(source_info, rvalue) {
+                if let Some(new) = new && self.should_simplify(source_info, rvalue) {
                     *rvalue = new;
                 }
             }
@@ -109,14 +109,14 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
     }
 
     /// Transform "&(*a)" ==> "a".
-    fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+    fn simplify_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
         if let Rvalue::Ref(_, _, place) = rvalue {
             if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
                 if rvalue.ty(self.local_decls, self.tcx) != base.ty(self.local_decls, self.tcx).ty {
                     return;
                 }
 
-                if !self.should_combine(source_info, rvalue) {
+                if !self.should_simplify(source_info, rvalue) {
                     return;
                 }
 
@@ -129,11 +129,11 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
     }
 
     /// Transform "Len([_; N])" ==> "N".
-    fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+    fn simplify_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
         if let Rvalue::Len(ref place) = *rvalue {
             let place_ty = place.ty(self.local_decls, self.tcx).ty;
             if let ty::Array(_, len) = *place_ty.kind() {
-                if !self.should_combine(source_info, rvalue) {
+                if !self.should_simplify(source_info, rvalue) {
                     return;
                 }
 
@@ -144,7 +144,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
         }
     }
 
-    fn combine_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+    fn simplify_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
         if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
             let operand_ty = operand.ty(self.local_decls, self.tcx);
             if operand_ty == *cast_ty {
@@ -196,7 +196,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
         }
     }
 
-    fn combine_primitive_clone(
+    fn simplify_primitive_clone(
         &self,
         terminator: &mut Terminator<'tcx>,
         statements: &mut Vec<Statement<'tcx>>,
@@ -239,7 +239,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
 
         if !self.tcx.consider_optimizing(|| {
             format!(
-                "InstCombine - Call: {:?} SourceInfo: {:?}",
+                "InstSimplify - Call: {:?} SourceInfo: {:?}",
                 (fn_def_id, fn_substs),
                 terminator.source_info
             )
@@ -262,7 +262,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
         terminator.kind = TerminatorKind::Goto { target: destination_block };
     }
 
-    fn combine_intrinsic_assert(
+    fn simplify_intrinsic_assert(
         &self,
         terminator: &mut Terminator<'tcx>,
         _statements: &mut Vec<Statement<'tcx>>,
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 8d9a22ea30d..5c4b1ead4e9 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,4 +1,6 @@
 #![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
 #![feature(let_chains)]
@@ -69,11 +71,12 @@ pub mod dump_mir;
 mod early_otherwise_branch;
 mod elaborate_box_derefs;
 mod elaborate_drops;
+mod errors;
 mod ffi_unwind_calls;
 mod function_item_references;
 mod generator;
 mod inline;
-mod instcombine;
+mod instsimplify;
 mod large_enums;
 mod lower_intrinsics;
 mod lower_slice_len;
@@ -105,6 +108,11 @@ use rustc_const_eval::transform::promote_consts;
 use rustc_const_eval::transform::validate;
 use rustc_mir_dataflow::rustc_peek;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
+
+fluent_messages! { "../messages.ftl" }
+
 pub fn provide(providers: &mut Providers) {
     check_unsafety::provide(providers);
     coverage::query::provide(providers);
@@ -547,7 +555,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &match_branches::MatchBranchSimplification,
             // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
             &multiple_return_terminators::MultipleReturnTerminators,
-            &instcombine::InstCombine,
+            &instsimplify::InstSimplify,
             &separate_const_switch::SeparateConstSwitch,
             &simplify::SimplifyLocals::BeforeConstProp,
             &copy_prop::CopyProp,
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 69ba4840146..dae01e41e5f 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -1,6 +1,6 @@
 //! Lowers intrinsic calls
 
-use crate::MirPass;
+use crate::{errors, MirPass};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -310,11 +310,7 @@ fn resolve_rust_intrinsic<'tcx>(
 }
 
 fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
-    match &args[2] {
-        Operand::Constant(_) => {} // all good
-        _ => {
-            let msg = "last argument of `simd_shuffle` is required to be a `const` item";
-            tcx.sess.span_err(span, msg);
-        }
+    if !matches!(args[2], Operand::Constant(_)) {
+        tcx.sess.emit_err(errors::SimdShuffleLastConst { span });
     }
 }
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index b6e73eaad50..85b26220b1e 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -34,7 +34,8 @@ pub struct RenameReturnPlace;
 
 impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() > 0
+        // #111005
+        sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 7e0cef025f7..1b96df3aed5 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -278,7 +278,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
     }
 }
 
-pub fn combine_duplicate_switch_targets(terminator: &mut Terminator<'_>) {
+pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) {
     if let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind {
         let otherwise = targets.otherwise();
         if targets.iter().any(|t| t.1 == otherwise) {
@@ -310,7 +310,7 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B
                 }
             }
 
-            combine_duplicate_switch_targets(terminator);
+            simplify_duplicate_switch_targets(terminator);
 
             self.super_terminator(terminator, location);
         }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 65162477b7b..55c937b305a 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
         self.instance.subst_mir_and_normalize_erasing_regions(
             self.tcx,
             ty::ParamEnv::reveal_all(),
-            value,
+            ty::EarlyBinder(value),
         )
     }
 }
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 03183a40660..37b7f6bf8a8 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -310,7 +310,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
                     let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
                         instance.substs,
                         ty::ParamEnv::reveal_all(),
-                        tcx.type_of(impl_def_id).skip_binder(),
+                        tcx.type_of(impl_def_id),
                     );
                     if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
                         return Some(def_id);
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index 33e1f6ce342..d12bfc6f6bb 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
         let before_feature_tys = tcx.subst_and_normalize_erasing_regions(
             closure_instance.substs,
             param_env,
-            before_feature_tys,
+            ty::EarlyBinder(before_feature_tys),
         );
         let after_feature_tys = tcx.subst_and_normalize_erasing_regions(
             closure_instance.substs,
             param_env,
-            after_feature_tys,
+            ty::EarlyBinder(after_feature_tys),
         );
 
         let new_size = tcx
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index a01e6f5ba11..1bbf833e3cd 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -257,6 +257,10 @@ parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are inva
     .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
     .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
 
+parse_expected_builtin_ident = expected identifier after `builtin #`
+
+parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}`
+
 parse_non_string_abi_literal = non-string ABI literal
     .suggestion = specify the ABI with a string literal
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 4dffdae1dc9..b6aeaf3d59f 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2656,3 +2656,18 @@ pub(crate) struct MalformedCfgAttr {
     pub span: Span,
     pub sugg: &'static str,
 }
+
+#[derive(Diagnostic)]
+#[diag(parse_unknown_builtin_construct)]
+pub(crate) struct UnknownBuiltinConstruct {
+    #[primary_span]
+    pub span: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_builtin_ident)]
+pub(crate) struct ExpectedBuiltinIdent {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 018eddea4b0..887e155426f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1300,6 +1300,8 @@ impl<'a> Parser<'a> {
             })
         } else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
             self.parse_expr_array_or_repeat(Delimiter::Bracket)
+        } else if self.is_builtin() {
+            self.parse_expr_builtin()
         } else if self.check_path() {
             self.parse_expr_path_start()
         } else if self.check_keyword(kw::Move)
@@ -1766,6 +1768,61 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr)
     }
 
+    /// Parse `builtin # ident(args,*)`.
+    fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
+        self.parse_builtin(|this, lo, ident| {
+            if ident.name == sym::offset_of {
+                return Ok(Some(this.parse_expr_offset_of(lo)?));
+            }
+
+            Ok(None)
+        })
+    }
+
+    pub(crate) fn parse_builtin<T>(
+        &mut self,
+        parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
+    ) -> PResult<'a, T> {
+        let lo = self.token.span;
+
+        self.bump(); // `builtin`
+        self.bump(); // `#`
+
+        let Some((ident, false)) = self.token.ident() else {
+            let err = errors::ExpectedBuiltinIdent { span: self.token.span }
+                .into_diagnostic(&self.sess.span_diagnostic);
+            return Err(err);
+        };
+        self.sess.gated_spans.gate(sym::builtin_syntax, ident.span);
+        self.bump();
+
+        self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
+        let ret = if let Some(res) = parse(self, lo, ident)? {
+            Ok(res)
+        } else {
+            let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
+                .into_diagnostic(&self.sess.span_diagnostic);
+            return Err(err);
+        };
+        self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
+
+        ret
+    }
+
+    pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+        let container = self.parse_ty()?;
+        self.expect(&TokenKind::Comma)?;
+
+        let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false };
+        let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
+            &TokenKind::CloseDelim(Delimiter::Parenthesis),
+            seq_sep,
+            Parser::parse_field_name,
+        )?;
+        let span = lo.to(self.token.span);
+        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
+    }
+
     /// Returns a string literal if the next token is a string literal.
     /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
     /// and returns `None` if the next token is not literal at all.
@@ -2835,6 +2892,10 @@ impl<'a> Parser<'a> {
         })
     }
 
+    pub(crate) fn is_builtin(&self) -> bool {
+        self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
+    }
+
     /// Parses a `try {...}` expression (`try` token already eaten).
     fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 6ca88200dc5..840cfe90899 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -265,6 +265,9 @@ impl<'a> Parser<'a> {
             // UNION ITEM
             self.bump(); // `union`
             self.parse_item_union()?
+        } else if self.is_builtin() {
+            // BUILTIN# ITEM
+            return self.parse_item_builtin();
         } else if self.eat_keyword(kw::Macro) {
             // MACROS 2.0 ITEM
             self.parse_item_decl_macro(lo)?
@@ -434,6 +437,11 @@ impl<'a> Parser<'a> {
         }
     }
 
+    fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
+        // To be expanded
+        return Ok(None);
+    }
+
     /// Parses an item macro, e.g., `item!();`.
     fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
         let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
@@ -1262,6 +1270,7 @@ impl<'a> Parser<'a> {
             }
         }
 
+        let prev_span = self.prev_token.span;
         let id = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
         generics.where_clause = self.parse_where_clause()?;
@@ -1273,10 +1282,28 @@ impl<'a> Parser<'a> {
             (thin_vec![], false)
         } else {
             self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
-                |mut e| {
-                    e.span_label(id.span, "while parsing this enum");
+                |mut err| {
+                    err.span_label(id.span, "while parsing this enum");
+                    if self.token == token::Colon {
+                        let snapshot = self.create_snapshot_for_diagnostic();
+                        self.bump();
+                        match self.parse_ty() {
+                            Ok(_) => {
+                                err.span_suggestion_verbose(
+                                    prev_span,
+                                    "perhaps you meant to use `struct` here",
+                                    "struct".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            Err(e) => {
+                                e.cancel();
+                            }
+                        }
+                        self.restore_snapshot(snapshot);
+                    }
                     self.recover_stmt();
-                    e
+                    err
                 },
             )?
         };
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index c35c32f272a..03279124177 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -90,7 +90,11 @@ impl<'a> Parser<'a> {
                 attrs,
                 errors::InvalidVariableDeclarationSub::UseLetNotVar,
             )?
-        } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
+        } else if self.check_path()
+            && !self.token.is_qpath_start()
+            && !self.is_path_start_item()
+            && !self.is_builtin()
+        {
             // We have avoided contextual keywords like `union`, items with `crate` visibility,
             // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
             // that starts like a path (1 token), but it fact not a path.
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index b738ce35ada..f27b8d9df1a 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -243,6 +243,39 @@ where
                 // This will also visit substs if necessary, so we don't need to recurse.
                 return self.visit_projection_ty(proj);
             }
+            ty::Alias(ty::Inherent, data) => {
+                if self.def_id_visitor.skip_assoc_tys() {
+                    // Visitors searching for minimal visibility/reachability want to
+                    // conservatively approximate associated types like `Type::Alias`
+                    // as visible/reachable even if `Type` is private.
+                    // Ideally, associated types should be substituted in the same way as
+                    // free type aliases, but this isn't done yet.
+                    return ControlFlow::Continue(());
+                }
+
+                self.def_id_visitor.visit_def_id(
+                    data.def_id,
+                    "associated type",
+                    &LazyDefPathStr { def_id: data.def_id, tcx },
+                )?;
+
+                struct LazyDefPathStr<'tcx> {
+                    def_id: DefId,
+                    tcx: TyCtxt<'tcx>,
+                }
+                impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
+                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                        write!(f, "{}", self.tcx.def_path_str(self.def_id))
+                    }
+                }
+
+                // This will also visit substs if necessary, so we don't need to recurse.
+                return if self.def_id_visitor.shallow() {
+                    ControlFlow::Continue(())
+                } else {
+                    data.substs.iter().try_for_each(|subst| subst.visit_with(self))
+                };
+            }
             ty::Dynamic(predicates, ..) => {
                 // All traits in the list are considered the "primary" part of the type
                 // and are visited by shallow visitors.
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index d80cc0aa043..aa3cb03bad8 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -599,6 +599,7 @@ pub enum PrintRequest {
     StackProtectorStrategies,
     LinkArgs,
     SplitDebuginfo,
+    DeploymentTarget,
 }
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
@@ -1481,7 +1482,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
              target-list|target-cpus|target-features|relocation-models|code-models|\
              tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
-             stack-protector-strategies|link-args]",
+             stack-protector-strategies|link-args|deployment-target]",
         ),
         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1931,6 +1932,7 @@ fn collect_print_requests(
         ("all-target-specs-json", PrintRequest::AllTargetSpecs),
         ("link-args", PrintRequest::LinkArgs),
         ("split-debuginfo", PrintRequest::SplitDebuginfo),
+        ("deployment-target", PrintRequest::DeploymentTarget),
     ];
 
     prints.extend(matches.opt_strs("print").into_iter().map(|req| {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 243da98c3c2..5cbd7f98b6b 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1555,7 +1555,7 @@ options! {
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
     mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
-        "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
+        "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the specified passes to be \
         enabled, overriding all other checks. Passes that are not specified are enabled or \
         disabled by other flags as usual."),
     mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b97ec6c684b..117e2774bd8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -95,6 +95,7 @@ symbols! {
 
         // Weak keywords, have special meaning only in specific contexts.
         Auto:               "auto",
+        Builtin:            "builtin",
         Catch:              "catch",
         Default:            "default",
         MacroRules:         "macro_rules",
@@ -440,6 +441,7 @@ symbols! {
         breakpoint,
         bridge,
         bswap,
+        builtin_syntax,
         c_str,
         c_str_literals,
         c_unwind,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 57011aa8a14..52159a7b06a 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -65,7 +65,7 @@ mod attr_impl {
     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
     bitflags::bitflags! {
         #[derive(Default, HashStable_Generic)]
-        pub struct ArgAttribute: u16 {
+        pub struct ArgAttribute: u8 {
             const NoAlias   = 1 << 1;
             const NoCapture = 1 << 2;
             const NonNull   = 1 << 3;
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
index 7ace1647ded..9d1a4f3eeea 100644
--- a/compiler/rustc_target/src/asm/loongarch.rs
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -33,12 +33,11 @@ impl LoongArchInlineAsmRegClass {
 
     pub fn supported_types(
         self,
-        arch: InlineAsmArch,
+        _arch: InlineAsmArch,
     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
-        match (self, arch) {
-            (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; },
-            (Self::reg, _) => types! { _: I8, I16, I32, F32; },
-            (Self::freg, _) => types! { _: F32, F64; },
+        match self {
+            Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
+            Self::freg => types! { _: F32, F64; },
         }
     }
 }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 4c7f64b2078..ff224631828 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,7 +1,7 @@
 use std::{borrow::Cow, env};
 
 use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs};
-use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, TargetOptions};
+use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, Target, TargetOptions};
 
 #[cfg(test)]
 #[path = "apple/tests.rs"]
@@ -179,12 +179,28 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
     }
 }
 
-fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
-    let deployment_target = env::var(var_name).ok();
-    deployment_target
-        .as_ref()
-        .and_then(|s| s.split_once('.'))
-        .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
+pub fn deployment_target(target: &Target) -> Option<String> {
+    let (major, minor) = match &*target.os {
+        "macos" => {
+            // This does not need to be specific. It just needs to handle x86 vs M1.
+            let arch = if target.arch == "x86" || target.arch == "x86_64" { X86_64 } else { Arm64 };
+            macos_deployment_target(arch)
+        }
+        "ios" => ios_deployment_target(),
+        "watchos" => watchos_deployment_target(),
+        "tvos" => tvos_deployment_target(),
+        _ => return None,
+    };
+
+    Some(format!("{major}.{minor}"))
+}
+
+fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> {
+    let deployment_target = env::var(var_name).ok()?;
+    let (unparsed_major, unparsed_minor) = deployment_target.split_once('.')?;
+    let (major, minor) = (unparsed_major.parse().ok()?, unparsed_minor.parse().ok()?);
+
+    Some((major, minor))
 }
 
 fn macos_default_deployment_target(arch: Arch) -> (u32, u32) {
@@ -198,7 +214,8 @@ fn macos_default_deployment_target(arch: Arch) -> (u32, u32) {
 }
 
 fn macos_deployment_target(arch: Arch) -> (u32, u32) {
-    deployment_target("MACOSX_DEPLOYMENT_TARGET")
+    // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    from_set_deployment_target("MACOSX_DEPLOYMENT_TARGET")
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
 
@@ -247,7 +264,8 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]>
 }
 
 fn ios_deployment_target() -> (u32, u32) {
-    deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+    // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
 }
 
 pub fn ios_llvm_target(arch: Arch) -> String {
@@ -272,7 +290,8 @@ pub fn ios_sim_llvm_target(arch: Arch) -> String {
 }
 
 fn tvos_deployment_target() -> (u32, u32) {
-    deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+    // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
 }
 
 fn tvos_lld_platform_version() -> String {
@@ -281,7 +300,8 @@ fn tvos_lld_platform_version() -> String {
 }
 
 fn watchos_deployment_target() -> (u32, u32) {
-    deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
+    // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
 fn watchos_lld_platform_version() -> String {
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index f6f46aac4c3..5632bcfcefe 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -16,7 +16,7 @@ pub fn target() -> Target {
             linker: Some("rust-lld".into()),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(64),
             emit_debug_gdb_scripts: false,
             // GCC and Clang default to 8 for arm-none here
             c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index 9608efe8bcf..2815de3589d 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
             features: "+vfp3,-d32,-fp16".into(),
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(64),
             emit_debug_gdb_scripts: false,
             // GCC and Clang default to 8 for arm-none here
             c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
index ebd2cca25ea..e2c0808f1fd 100644
--- a/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
@@ -9,7 +9,7 @@ pub fn target() -> Target {
     let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,-q"]);
 
     Target {
-        llvm_target: "armv7a-vita-newlibeabihf".into(),
+        llvm_target: "armv7a-vita-eabihf".into(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
         arch: "arm".into(),
@@ -33,7 +33,7 @@ pub fn target() -> Target {
             pre_link_args,
             exe_suffix: ".elf".into(),
             panic_strategy: PanicStrategy::Abort,
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(64),
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index 5225abf44fc..74905ed5a4e 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> Target {
             linker: Some("rust-lld".into()),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(64),
             emit_debug_gdb_scripts: false,
             // GCC and Clang default to 8 for arm-none here
             c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 9a35e04617f..516b3f5c17e 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -16,7 +16,7 @@ pub fn target() -> Target {
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
             features: "+vfp3,-d32,-fp16".into(),
-            max_atomic_width: Some(32),
+            max_atomic_width: Some(64),
             emit_debug_gdb_scripts: false,
             // GCC and Clang default to 8 for arm-none here
             c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 10d38c34919..ba4b89c9ea1 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -60,6 +60,7 @@ pub mod crt_objects;
 mod aix_base;
 mod android_base;
 mod apple_base;
+pub use apple_base::deployment_target as current_apple_deployment_target;
 mod avr_gnu_base;
 mod bpf_base;
 mod dragonfly_base;
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 14eb4a5502d..8fea3fc140d 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -20,3 +20,5 @@ trait_selection_negative_positive_conflict = found both positive and negative im
     .negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
     .positive_implementation_here = positive implementation here
     .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
+
+trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index df7c4df1868..54e22cc3d7f 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
         diag
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_inherent_projection_normalization_overflow)]
+pub struct InherentProjectionNormalizationOverflow {
+    #[primary_span]
+    pub span: Span,
+    pub ty: String,
+}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 996dc329dcb..0ede32c753c 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         ty::Dynamic(..)
         | ty::Param(..)
         | ty::Foreign(..)
-        | ty::Alias(ty::Projection, ..)
+        | ty::Alias(ty::Projection | ty::Inherent, ..)
         | ty::Placeholder(..)
         | ty::Bound(..)
         | ty::Infer(_) => {
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 6c98fadd148..04b38edc126 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -655,7 +655,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ty::Dynamic(..)
             | ty::Param(..)
             | ty::Foreign(..)
-            | ty::Alias(ty::Projection, ..)
+            | ty::Alias(ty::Projection | ty::Inherent, ..)
             | ty::Placeholder(..) => Some(Err(NoSolution)),
 
             ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index b7690f79933..402b09419c8 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -673,7 +673,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
             | ty::RawPtr(..)
             | ty::Never
             | ty::Tuple(..)
-            | ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
+            | ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
 
             ty::Param(..) => self.found_param_ty(ty),
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index afb64da8b61..c9e2ed092d1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1687,13 +1687,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ty::Tuple(..) => Some(10),
                 ty::Param(..) => Some(11),
                 ty::Alias(ty::Projection, ..) => Some(12),
-                ty::Alias(ty::Opaque, ..) => Some(13),
-                ty::Never => Some(14),
-                ty::Adt(..) => Some(15),
-                ty::Generator(..) => Some(16),
-                ty::Foreign(..) => Some(17),
-                ty::GeneratorWitness(..) => Some(18),
-                ty::GeneratorWitnessMIR(..) => Some(19),
+                ty::Alias(ty::Inherent, ..) => Some(13),
+                ty::Alias(ty::Opaque, ..) => Some(14),
+                ty::Never => Some(15),
+                ty::Adt(..) => Some(16),
+                ty::Generator(..) => Some(17),
+                ty::Foreign(..) => Some(18),
+                ty::GeneratorWitness(..) => Some(19),
+                ty::GeneratorWitnessMIR(..) => Some(20),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d8e5725d3ca..b162e5b8995 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -49,7 +49,8 @@ pub use self::object_safety::astconv_object_safety_violations;
 pub use self::object_safety::is_vtable_safe_method;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::ObjectSafetyViolation;
-pub use self::project::{normalize_projection_type, NormalizeExt};
+pub use self::project::NormalizeExt;
+pub use self::project::{normalize_inherent_projection, normalize_projection_type};
 pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
 pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
 pub use self::specialize::specialization_graph::FutureCompatOverlapError;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8c74860cdf3..8e684b7ac23 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -16,6 +16,7 @@ use super::{
 };
 use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
 
+use crate::errors::InherentProjectionNormalizationOverflow;
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use crate::traits::error_reporting::TypeErrCtxtExt as _;
@@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
     reveal: Reveal,
 ) -> bool {
     match reveal {
-        Reveal::UserFacing => value
-            .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
+        Reveal::UserFacing => value.has_type_flags(
+            ty::TypeFlags::HAS_TY_PROJECTION
+                | ty::TypeFlags::HAS_TY_INHERENT
+                | ty::TypeFlags::HAS_CT_PROJECTION,
+        ),
         Reveal::All => value.has_type_flags(
             ty::TypeFlags::HAS_TY_PROJECTION
+                | ty::TypeFlags::HAS_TY_INHERENT
                 | ty::TypeFlags::HAS_TY_OPAQUE
                 | ty::TypeFlags::HAS_CT_PROJECTION,
         ),
@@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 );
                 normalized_ty
             }
+
+            ty::Inherent if !data.has_escaping_bound_vars() => {
+                // This branch is *mostly* just an optimization: when we don't
+                // have escaping bound vars, we don't need to replace them with
+                // placeholders (see branch below). *Also*, we know that we can
+                // register an obligation to *later* project, since we know
+                // there won't be bound vars there.
+
+                let data = data.fold_with(self);
+
+                // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
+                // here like `ty::Projection`?
+                normalize_inherent_projection(
+                    self.selcx,
+                    self.param_env,
+                    data,
+                    self.cause.clone(),
+                    self.depth,
+                    &mut self.obligations,
+                )
+            }
+
+            ty::Inherent => {
+                let infcx = self.selcx.infcx;
+                let (data, mapped_regions, mapped_types, mapped_consts) =
+                    BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+                let data = data.fold_with(self);
+                let ty = normalize_inherent_projection(
+                    self.selcx,
+                    self.param_env,
+                    data,
+                    self.cause.clone(),
+                    self.depth,
+                    &mut self.obligations,
+                );
+
+                PlaceholderReplacer::replace_placeholders(
+                    infcx,
+                    mapped_regions,
+                    mapped_types,
+                    mapped_consts,
+                    &self.universes,
+                    ty,
+                )
+            }
         }
     }
 
@@ -1204,6 +1254,115 @@ fn normalize_to_error<'a, 'tcx>(
     Normalized { value: new_value, obligations: vec![trait_obligation] }
 }
 
+/// Confirm and normalize the given inherent projection.
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
+pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
+    selcx: &'a mut SelectionContext<'b, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    alias_ty: ty::AliasTy<'tcx>,
+    cause: ObligationCause<'tcx>,
+    depth: usize,
+    obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> Ty<'tcx> {
+    let tcx = selcx.tcx();
+
+    if !tcx.recursion_limit().value_within_limit(depth) {
+        // Halt compilation because it is important that overflows never be masked.
+        tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
+            span: cause.span,
+            ty: alias_ty.to_string(),
+        });
+    }
+
+    let substs = compute_inherent_assoc_ty_substs(
+        selcx,
+        param_env,
+        alias_ty,
+        cause.clone(),
+        depth,
+        obligations,
+    );
+
+    // Register the obligations arising from the impl and from the associated type itself.
+    let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
+    for (predicate, span) in predicates {
+        let predicate = normalize_with_depth_to(
+            selcx,
+            param_env,
+            cause.clone(),
+            depth + 1,
+            predicate,
+            obligations,
+        );
+
+        let nested_cause = ObligationCause::new(
+            cause.span,
+            cause.body_id,
+            // FIXME(inherent_associated_types): Since we can't pass along the self type to the
+            // cause code, inherent projections will be printed with identity substitutions in
+            // diagnostics which is not ideal.
+            // Consider creating separate cause codes for this specific situation.
+            if span.is_dummy() {
+                super::ItemObligation(alias_ty.def_id)
+            } else {
+                super::BindingObligation(alias_ty.def_id, span)
+            },
+        );
+
+        obligations.push(Obligation::with_depth(
+            tcx,
+            nested_cause,
+            depth + 1,
+            param_env,
+            predicate,
+        ));
+    }
+
+    let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs);
+
+    let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
+    if ty.has_projections() {
+        ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
+    }
+
+    ty
+}
+
+pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>(
+    selcx: &'a mut SelectionContext<'b, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    alias_ty: ty::AliasTy<'tcx>,
+    cause: ObligationCause<'tcx>,
+    depth: usize,
+    obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> ty::SubstsRef<'tcx> {
+    let tcx = selcx.tcx();
+
+    let impl_def_id = tcx.parent(alias_ty.def_id);
+    let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
+
+    let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
+    let impl_ty =
+        normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
+
+    // Infer the generic parameters of the impl by unifying the
+    // impl type with the self type of the projection.
+    let self_ty = alias_ty.self_ty();
+    match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
+        Ok(mut ok) => obligations.append(&mut ok.obligations),
+        Err(_) => {
+            tcx.sess.delay_span_bug(
+                cause.span,
+                format!(
+                    "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
+                ),
+            );
+        }
+    }
+
+    alias_ty.rebase_substs_onto_impl(impl_substs, tcx)
+}
+
 enum Projected<'tcx> {
     Progress(Progress<'tcx>),
     NoProgress(ty::Term<'tcx>),
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index a986a9b6a71..8bf934cb78a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
 
             ty::Opaque => ty.try_super_fold_with(self)?,
 
-            ty::Projection => {
+            ty::Projection | ty::Inherent => {
                 // See note in `rustc_trait_selection::traits::project`
 
-                let tcx = self.infcx.tcx;
                 let infcx = self.infcx;
+                let tcx = infcx.tcx;
                 // Just an optimization: When we don't have escaping bound vars,
                 // we don't need to replace them with placeholders.
                 let (data, maps) = if data.has_escaping_bound_vars() {
@@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                 let mut orig_values = OriginalQueryValues::default();
                 // HACK(matthewjasper) `'static` is special-cased in selection,
                 // so we cannot canonicalize it.
-                let c_data = self
-                    .infcx
+                let c_data = infcx
                     .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
-                let result = tcx.normalize_projection_ty(c_data)?;
+                let result = match kind {
+                    ty::Projection => tcx.normalize_projection_ty(c_data),
+                    ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
+                    _ => unreachable!(),
+                }?;
                 // We don't expect ambiguity.
                 if result.is_ambiguous() {
                     // Rustdoc normalizes possibly not well-formed types, so only
@@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                     }
                     return Err(NoSolution);
                 }
-                let InferOk { value: result, obligations } =
-                    self.infcx.instantiate_query_response_and_region_obligations(
+                let InferOk { value: result, obligations } = infcx
+                    .instantiate_query_response_and_region_obligations(
                         self.cause,
                         self.param_env,
                         &orig_values,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 33f502f8182..a8fb55df2d3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -498,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     // this trait and type.
                 }
                 ty::Param(..)
-                | ty::Alias(ty::Projection, ..)
+                | ty::Alias(ty::Projection | ty::Inherent, ..)
                 | ty::Placeholder(..)
                 | ty::Bound(..) => {
                     // In these cases, we don't know what the actual
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 422285d9474..616187b69dd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1268,7 +1268,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // If we have a projection type, make sure to normalize it so we replace it
                 // with a fresh infer variable
-                ty::Alias(ty::Projection, ..) => {
+                ty::Alias(ty::Projection | ty::Inherent, ..) => {
                     let predicate = normalize_with_depth_to(
                         self,
                         obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 246d3ea2ef2..e4f5a84f424 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2315,7 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Dynamic(..)
             | ty::Param(..)
             | ty::Foreign(..)
-            | ty::Alias(ty::Projection, ..)
+            | ty::Alias(ty::Projection | ty::Inherent, ..)
             | ty::Bound(..)
             | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble constituent types of unexpected type: {:?}", t);
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 22710c7c059..086ab32b520 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -58,15 +58,8 @@ pub fn obligations<'tcx>(
         GenericArgKind::Lifetime(..) => return Some(Vec::new()),
     };
 
-    let mut wf = WfPredicates {
-        tcx: infcx.tcx,
-        param_env,
-        body_id,
-        span,
-        out: vec![],
-        recursion_depth,
-        item: None,
-    };
+    let mut wf =
+        WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
     wf.compute(arg);
     debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
 
@@ -91,7 +84,7 @@ pub fn unnormalized_obligations<'tcx>(
     debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
 
     let mut wf = WfPredicates {
-        tcx: infcx.tcx,
+        infcx,
         param_env,
         body_id: CRATE_DEF_ID,
         span: DUMMY_SP,
@@ -116,7 +109,7 @@ pub fn trait_obligations<'tcx>(
     item: &'tcx hir::Item<'tcx>,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
     let mut wf = WfPredicates {
-        tcx: infcx.tcx,
+        infcx,
         param_env,
         body_id,
         span,
@@ -138,7 +131,7 @@ pub fn predicate_obligations<'tcx>(
     span: Span,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
     let mut wf = WfPredicates {
-        tcx: infcx.tcx,
+        infcx,
         param_env,
         body_id,
         span,
@@ -190,8 +183,8 @@ pub fn predicate_obligations<'tcx>(
     wf.normalize(infcx)
 }
 
-struct WfPredicates<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct WfPredicates<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_id: LocalDefId,
     span: Span,
@@ -290,9 +283,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
     }
 }
 
-impl<'tcx> WfPredicates<'tcx> {
+impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
+        self.infcx.tcx
     }
 
     fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
@@ -325,7 +318,7 @@ impl<'tcx> WfPredicates<'tcx> {
 
     /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
     fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
-        let tcx = self.tcx;
+        let tcx = self.tcx();
         let trait_ref = &trait_pred.trait_ref;
 
         // Negative trait predicates don't require supertraits to hold, just
@@ -369,7 +362,6 @@ impl<'tcx> WfPredicates<'tcx> {
             self.out.extend(obligations);
         }
 
-        let tcx = self.tcx();
         self.out.extend(
             trait_ref
                 .substs
@@ -436,13 +428,45 @@ impl<'tcx> WfPredicates<'tcx> {
         let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
         self.out.extend(obligations);
 
+        self.compute_projection_substs(data.substs);
+    }
+
+    fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
+        // An inherent projection is well-formed if
+        //
+        // (a) its predicates hold (*)
+        // (b) its substs are wf
+        //
+        // (*) The predicates of an inherent associated type include the
+        //     predicates of the impl that it's contained in.
+
+        if !data.self_ty().has_escaping_bound_vars() {
+            // FIXME(inherent_associated_types): Should this happen inside of a snapshot?
+            // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
+            let substs = traits::project::compute_inherent_assoc_ty_substs(
+                &mut traits::SelectionContext::new(self.infcx),
+                self.param_env,
+                data,
+                self.cause(traits::WellFormed(None)),
+                self.recursion_depth,
+                &mut self.out,
+            );
+            // Inherent projection types do not require const predicates.
+            let obligations = self.nominal_obligations_without_const(data.def_id, substs);
+            self.out.extend(obligations);
+        }
+
+        self.compute_projection_substs(data.substs);
+    }
+
+    fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) {
         let tcx = self.tcx();
         let cause = self.cause(traits::WellFormed(None));
         let param_env = self.param_env;
         let depth = self.recursion_depth;
 
         self.out.extend(
-            data.substs
+            substs
                 .iter()
                 .filter(|arg| {
                     matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
@@ -464,9 +488,9 @@ impl<'tcx> WfPredicates<'tcx> {
         if !subty.has_escaping_bound_vars() {
             let cause = self.cause(cause);
             let trait_ref =
-                ty::TraitRef::from_lang_item(self.tcx, LangItem::Sized, cause.span, [subty]);
+                ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]);
             self.out.push(traits::Obligation::with_depth(
-                self.tcx,
+                self.tcx(),
                 cause,
                 self.recursion_depth,
                 self.param_env,
@@ -605,6 +629,10 @@ impl<'tcx> WfPredicates<'tcx> {
                     walker.skip_current_subtree(); // Subtree handled by compute_projection.
                     self.compute_projection(data);
                 }
+                ty::Alias(ty::Inherent, data) => {
+                    walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection.
+                    self.compute_inherent_projection(data);
+                }
 
                 ty::Adt(def, substs) => {
                     // WfNominalType
@@ -697,7 +725,7 @@ impl<'tcx> WfPredicates<'tcx> {
                     // All of the requirements on type parameters
                     // have already been checked for `impl Trait` in
                     // return position. We do need to check type-alias-impl-trait though.
-                    if self.tcx.is_type_alias_impl_trait(def_id) {
+                    if self.tcx().is_type_alias_impl_trait(def_id) {
                         let obligations = self.nominal_obligations(def_id, substs);
                         self.out.extend(obligations);
                     }
@@ -767,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> {
         substs: SubstsRef<'tcx>,
         remap_constness: bool,
     ) -> Vec<traits::PredicateObligation<'tcx>> {
-        let predicates = self.tcx.predicates_of(def_id);
+        let predicates = self.tcx().predicates_of(def_id);
         let mut origins = vec![def_id; predicates.predicates.len()];
         let mut head = predicates;
         while let Some(parent) = head.parent {
-            head = self.tcx.predicates_of(parent);
+            head = self.tcx().predicates_of(parent);
             origins.extend(iter::repeat(parent).take(head.predicates.len()));
         }
 
-        let predicates = predicates.instantiate(self.tcx, substs);
+        let predicates = predicates.instantiate(self.tcx(), substs);
         trace!("{:#?}", predicates);
         debug_assert_eq!(predicates.predicates.len(), origins.len());
 
@@ -788,10 +816,10 @@ impl<'tcx> WfPredicates<'tcx> {
                 };
                 let cause = self.cause(code);
                 if remap_constness {
-                    pred = pred.without_const(self.tcx);
+                    pred = pred.without_const(self.tcx());
                 }
                 traits::Obligation::with_depth(
-                    self.tcx,
+                    self.tcx(),
                     cause,
                     self.recursion_depth,
                     self.param_env,
@@ -856,7 +884,7 @@ impl<'tcx> WfPredicates<'tcx> {
         // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
         // am looking forward to the future here.
         if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
-            let implicit_bounds = object_region_bounds(self.tcx, data);
+            let implicit_bounds = object_region_bounds(self.tcx(), data);
 
             let explicit_bound = region;
 
@@ -866,7 +894,7 @@ impl<'tcx> WfPredicates<'tcx> {
                 let outlives =
                     ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
                 self.out.push(traits::Obligation::with_depth(
-                    self.tcx,
+                    self.tcx(),
                     cause,
                     self.recursion_depth,
                     self.param_env,
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 4d225e36b22..2f9e480d8bd 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
                     substitution: substs.lower_into(interner),
                 }))
             }
+            ty::Alias(ty::Inherent, _) => unimplemented!(),
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
                 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
                     opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index e805eb42821..36d80a06ee7 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
 use std::sync::atomic::Ordering;
 
 pub(crate) fn provide(p: &mut Providers) {
-    *p = Providers { normalize_projection_ty, ..*p };
+    *p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p };
 }
 
 fn normalize_projection_ty<'tcx>(
@@ -42,3 +42,30 @@ fn normalize_projection_ty<'tcx>(
         },
     )
 }
+
+fn normalize_inherent_projection_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal: CanonicalProjectionGoal<'tcx>,
+) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
+    debug!("normalize_provider(goal={:#?})", goal);
+
+    tcx.infer_ctxt().enter_canonical_trait_query(
+        &goal,
+        |ocx, ParamEnvAnd { param_env, value: goal }| {
+            let selcx = &mut SelectionContext::new(ocx.infcx);
+            let cause = ObligationCause::dummy();
+            let mut obligations = vec![];
+            let answer = traits::normalize_inherent_projection(
+                selcx,
+                param_env,
+                goal,
+                cause,
+                0,
+                &mut obligations,
+            );
+            ocx.register_obligations(obligations);
+
+            Ok(NormalizationResult { normalized_ty: answer })
+        },
+    )
+}
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index de1e1a527d5..9029ba2a51a 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -334,7 +334,7 @@ fn associated_type_for_impl_trait_in_trait(
             parent_count,
             params,
             param_def_id_to_index,
-            has_self: false,
+            has_self: opaque_ty_generics.has_self,
             has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
         }
     });
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index b10aaad5f2a..eb3c21163ab 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -27,8 +27,7 @@ fn resolve_instance<'tcx>(
         )
     } else {
         let ty = tcx.type_of(def);
-        let item_type =
-            tcx.subst_and_normalize_erasing_regions(substs, param_env, ty.skip_binder());
+        let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
 
         let def = match *item_type.kind() {
             ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => {
@@ -195,21 +194,18 @@ fn resolve_associated_item<'tcx>(
             })
         }
         traits::ImplSource::Future(future_data) => {
-            if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::poll {
-                // For compiler developers who'd like to add new items to `Future`,
-                // you either need to generate a shim body, or perhaps return
-                // `InstanceDef::Item` pointing to a trait default method body if
-                // it is given a default implementation by the trait.
-                span_bug!(
-                    tcx.def_span(future_data.generator_def_id),
-                    "no definition for `{trait_ref}::{}` for built-in async generator type",
-                    tcx.item_name(trait_item_id)
-                )
+            if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
+                // `Future::poll` is generated by the compiler.
+                Some(Instance {
+                    def: ty::InstanceDef::Item(future_data.generator_def_id),
+                    substs: future_data.substs,
+                })
+            } else {
+                // All other methods are default methods of the `Future` trait.
+                // (this assumes that `ImplSource::Future` is only used for methods on `Future`)
+                debug_assert!(tcx.impl_defaultness(trait_item_id).has_value());
+                Some(Instance::new(trait_item_id, rcvr_substs))
             }
-            Some(Instance {
-                def: ty::InstanceDef::Item(future_data.generator_def_id),
-                substs: future_data.substs,
-            })
         }
         traits::ImplSource::Closure(closure_data) => {
             if cfg!(debug_assertions)
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 1e91e26e2af..7e5a4d1c735 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -229,29 +229,32 @@ bitflags! {
 
         /// Does this have `Projection`?
         const HAS_TY_PROJECTION           = 1 << 10;
+        /// Does this have `Inherent`?
+        const HAS_TY_INHERENT             = 1 << 11;
         /// Does this have `Opaque`?
-        const HAS_TY_OPAQUE               = 1 << 11;
+        const HAS_TY_OPAQUE               = 1 << 12;
         /// Does this have `ConstKind::Unevaluated`?
-        const HAS_CT_PROJECTION           = 1 << 12;
+        const HAS_CT_PROJECTION           = 1 << 13;
 
         /// Could this type be normalized further?
         const HAS_PROJECTION              = TypeFlags::HAS_TY_PROJECTION.bits
                                           | TypeFlags::HAS_TY_OPAQUE.bits
+                                          | TypeFlags::HAS_TY_INHERENT.bits
                                           | TypeFlags::HAS_CT_PROJECTION.bits;
 
         /// Is an error type/const reachable?
-        const HAS_ERROR                   = 1 << 13;
+        const HAS_ERROR                   = 1 << 14;
 
         /// Does this have any region that "appears free" in the type?
         /// Basically anything but `ReLateBound` and `ReErased`.
-        const HAS_FREE_REGIONS            = 1 << 14;
+        const HAS_FREE_REGIONS            = 1 << 15;
 
         /// Does this have any `ReLateBound` regions?
-        const HAS_RE_LATE_BOUND           = 1 << 15;
+        const HAS_RE_LATE_BOUND           = 1 << 16;
         /// Does this have any `Bound` types?
-        const HAS_TY_LATE_BOUND           = 1 << 16;
+        const HAS_TY_LATE_BOUND           = 1 << 17;
         /// Does this have any `ConstKind::Bound` consts?
-        const HAS_CT_LATE_BOUND           = 1 << 17;
+        const HAS_CT_LATE_BOUND           = 1 << 18;
         /// Does this have any bound variables?
         /// Used to check if a global bound is safe to evaluate.
         const HAS_LATE_BOUND              = TypeFlags::HAS_RE_LATE_BOUND.bits
@@ -259,20 +262,20 @@ bitflags! {
                                           | TypeFlags::HAS_CT_LATE_BOUND.bits;
 
         /// Does this have any `ReErased` regions?
-        const HAS_RE_ERASED               = 1 << 18;
+        const HAS_RE_ERASED               = 1 << 19;
 
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
-        const STILL_FURTHER_SPECIALIZABLE = 1 << 19;
+        const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
 
         /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
-        const HAS_TY_FRESH                = 1 << 20;
+        const HAS_TY_FRESH                = 1 << 21;
 
         /// Does this value have `InferConst::Fresh`?
-        const HAS_CT_FRESH                = 1 << 21;
+        const HAS_CT_FRESH                = 1 << 22;
 
         /// Does this have `Generator` or `GeneratorWitness`?
-        const HAS_TY_GENERATOR            = 1 << 22;
+        const HAS_TY_GENERATOR            = 1 << 23;
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 4c1f2dd0e53..f7344bacc02 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -37,6 +37,7 @@ pub enum DynKind {
 #[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum AliasKind {
     Projection,
+    Inherent,
     Opaque,
 }