about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs39
-rw-r--r--compiler/rustc_ast_passes/messages.ftl2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs11
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs9
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs30
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs34
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs42
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs26
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_errors/Cargo.toml1
-rw-r--r--compiler/rustc_errors/src/emitter.rs77
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs34
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs30
-rw-r--r--compiler/rustc_lint/messages.ftl5
-rw-r--r--compiler/rustc_lint/src/lib.rs4
-rw-r--r--compiler/rustc_lint/src/lints.rs29
-rw-r--r--compiler/rustc_lint/src/precedence.rs70
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs2
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/mir/query.rs13
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs16
-rw-r--r--compiler/rustc_next_trait_solver/Cargo.toml2
-rw-r--r--compiler/rustc_next_trait_solver/src/coherence.rs7
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/inspect/build.rs22
-rw-r--r--compiler/rustc_parse/messages.ftl9
-rw-r--r--compiler/rustc_parse/src/errors.rs30
-rw-r--r--compiler/rustc_parse/src/parser/item.rs9
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs60
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs21
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs6
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_span/Cargo.toml2
-rw-r--r--compiler/rustc_span/src/analyze_source_file.rs40
-rw-r--r--compiler/rustc_span/src/analyze_source_file/tests.rs24
-rw-r--r--compiler/rustc_span/src/lib.rs143
-rw-r--r--compiler/rustc_span/src/source_map.rs2
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs308
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs6
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs15
-rw-r--r--compiler/rustc_type_ir/Cargo.toml2
-rw-r--r--compiler/rustc_type_ir/src/binder.rs37
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs42
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs16
-rw-r--r--compiler/rustc_type_ir/src/error.rs10
-rw-r--r--compiler/rustc_type_ir/src/generic_arg.rs19
-rw-r--r--compiler/rustc_type_ir/src/opaque_ty.rs11
-rw-r--r--compiler/rustc_type_ir/src/outlives.rs4
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs112
-rw-r--r--compiler/rustc_type_ir/src/predicate_kind.rs16
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs7
-rw-r--r--compiler/rustc_type_ir/src/relate.rs13
-rw-r--r--compiler/rustc_type_ir/src/search_graph/global_cache.rs15
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs7
-rw-r--r--compiler/rustc_type_ir/src/solve/inspect.rs44
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs84
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs39
-rw-r--r--compiler/rustc_type_ir/src/ty_kind/closure.rs51
-rw-r--r--compiler/stable_mir/Cargo.toml1
-rw-r--r--compiler/stable_mir/src/abi.rs35
-rw-r--r--compiler/stable_mir/src/crate_def.rs3
-rw-r--r--compiler/stable_mir/src/lib.rs10
-rw-r--r--compiler/stable_mir/src/mir/alloc.rs5
-rw-r--r--compiler/stable_mir/src/mir/body.rs81
-rw-r--r--compiler/stable_mir/src/mir/mono.rs10
-rw-r--r--compiler/stable_mir/src/target.rs7
-rw-r--r--compiler/stable_mir/src/ty.rs153
90 files changed, 1040 insertions, 1107 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 75c656973f9..564213ee7ee 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -36,6 +36,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
+use std::borrow::Cow;
 use std::cmp;
 use std::fmt;
 use std::mem;
@@ -2264,6 +2265,42 @@ bitflags::bitflags! {
     }
 }
 
+impl InlineAsmOptions {
+    pub fn human_readable_names(&self) -> Vec<&'static str> {
+        let mut options = vec![];
+
+        if self.contains(InlineAsmOptions::PURE) {
+            options.push("pure");
+        }
+        if self.contains(InlineAsmOptions::NOMEM) {
+            options.push("nomem");
+        }
+        if self.contains(InlineAsmOptions::READONLY) {
+            options.push("readonly");
+        }
+        if self.contains(InlineAsmOptions::PRESERVES_FLAGS) {
+            options.push("preserves_flags");
+        }
+        if self.contains(InlineAsmOptions::NORETURN) {
+            options.push("noreturn");
+        }
+        if self.contains(InlineAsmOptions::NOSTACK) {
+            options.push("nostack");
+        }
+        if self.contains(InlineAsmOptions::ATT_SYNTAX) {
+            options.push("att_syntax");
+        }
+        if self.contains(InlineAsmOptions::RAW) {
+            options.push("raw");
+        }
+        if self.contains(InlineAsmOptions::MAY_UNWIND) {
+            options.push("may_unwind");
+        }
+
+        options
+    }
+}
+
 impl std::fmt::Debug for InlineAsmOptions {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         bitflags::parser::to_writer(self, f)
@@ -2272,7 +2309,7 @@ impl std::fmt::Debug for InlineAsmOptions {
 
 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
 pub enum InlineAsmTemplatePiece {
-    String(String),
+    String(Cow<'static, str>),
     Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
 }
 
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index ca0b7f2ac3a..df5c639382f 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -155,8 +155,6 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
 ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
     .help = remove one of these features
 
-ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive
-
 ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
     .because = {$annotation} because of this
     .type = inherent impl for this type
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 34aac6e4473..1088db74cc9 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1366,17 +1366,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     {
                         self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
                     }
-                    (
-                        _,
-                        BoundConstness::Always(_) | BoundConstness::Maybe(_),
-                        BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
-                    ) => {
-                        self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
-                            span: bound.span(),
-                            left: modifiers.constness.as_str(),
-                            right: modifiers.polarity.as_str(),
-                        });
-                    }
                     _ => {}
                 }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 215ccd2ab4d..9151c4a7c7c 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -657,15 +657,6 @@ pub enum TildeConstReason {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_incompatible_trait_bound_modifiers)]
-pub struct IncompatibleTraitBoundModifiers {
-    #[primary_span]
-    pub span: Span,
-    pub left: &'static str,
-    pub right: &'static str,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_const_and_async)]
 pub struct ConstAndAsync {
     #[primary_span]
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 0568d368d8c..b463d1f36ce 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1505,35 +1505,7 @@ impl<'a> State<'a> {
             AsmArg::Options(opts) => {
                 s.word("options");
                 s.popen();
-                let mut options = vec![];
-                if opts.contains(InlineAsmOptions::PURE) {
-                    options.push("pure");
-                }
-                if opts.contains(InlineAsmOptions::NOMEM) {
-                    options.push("nomem");
-                }
-                if opts.contains(InlineAsmOptions::READONLY) {
-                    options.push("readonly");
-                }
-                if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
-                    options.push("preserves_flags");
-                }
-                if opts.contains(InlineAsmOptions::NORETURN) {
-                    options.push("noreturn");
-                }
-                if opts.contains(InlineAsmOptions::NOSTACK) {
-                    options.push("nostack");
-                }
-                if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
-                    options.push("att_syntax");
-                }
-                if opts.contains(InlineAsmOptions::RAW) {
-                    options.push("raw");
-                }
-                if opts.contains(InlineAsmOptions::MAY_UNWIND) {
-                    options.push("may_unwind");
-                }
-                s.commasep(Inconsistent, &options, |s, &opt| {
+                s.commasep(Inconsistent, &opts.human_readable_names(), |s, &opt| {
                     s.word(opt);
                 });
                 s.pclose();
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b147567001d..2d9bc45ebc8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -4304,17 +4304,35 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 // search for relevant arguments.
                 let mut arguments = Vec::new();
                 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
-                    if let ty::Ref(argument_region, _, _) = argument.kind() {
-                        if argument_region == return_region {
-                            // Need to use the `rustc_middle::ty` types to compare against the
-                            // `return_region`. Then use the `rustc_hir` type to get only
-                            // the lifetime span.
-                            if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
+                    if let ty::Ref(argument_region, _, _) = argument.kind()
+                        && argument_region == return_region
+                    {
+                        // Need to use the `rustc_middle::ty` types to compare against the
+                        // `return_region`. Then use the `rustc_hir` type to get only
+                        // the lifetime span.
+                        match &fn_decl.inputs[index].kind {
+                            hir::TyKind::Ref(lifetime, _) => {
                                 // With access to the lifetime, we can get
                                 // the span of it.
                                 arguments.push((*argument, lifetime.ident.span));
-                            } else {
-                                bug!("ty type is a ref but hir type is not");
+                            }
+                            // Resolve `self` whose self type is `&T`.
+                            hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
+                                if let Res::SelfTyAlias { alias_to, .. } = path.res
+                                    && let Some(alias_to) = alias_to.as_local()
+                                    && let hir::Impl { self_ty, .. } = self
+                                        .infcx
+                                        .tcx
+                                        .hir_node_by_def_id(alias_to)
+                                        .expect_item()
+                                        .expect_impl()
+                                    && let hir::TyKind::Ref(lifetime, _) = self_ty.kind
+                                {
+                                    arguments.push((*argument, lifetime.ident.span));
+                                }
+                            }
+                            _ => {
+                                // Don't ICE though. It might be a type alias.
                             }
                         }
                     }
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index dd0f9aaf221..b8fe6338493 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -459,7 +459,7 @@ fn expand_preparsed_asm(
 
     for (i, template_expr) in args.templates.into_iter().enumerate() {
         if i != 0 {
-            template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
+            template.push(ast::InlineAsmTemplatePiece::String("\n".into()));
         }
 
         let msg = "asm template must be a string literal";
@@ -527,7 +527,7 @@ fn expand_preparsed_asm(
 
         // Don't treat raw asm as a format string.
         if args.options.contains(ast::InlineAsmOptions::RAW) {
-            template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string()));
+            template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string().into()));
             let template_num_lines = 1 + template_str.matches('\n').count();
             line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
             continue;
@@ -577,7 +577,7 @@ fn expand_preparsed_asm(
         for piece in unverified_pieces {
             match piece {
                 parse::Piece::String(s) => {
-                    template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
+                    template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into()))
                 }
                 parse::Piece::NextArgument(arg) => {
                     let span = arg_spans.next().unwrap_or(template_sp);
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index c88230c9360..16edec47e10 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -46,9 +46,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
     // Used by panic_abort on Windows, but uses a syntax which only happens to work with
     // asm!() by accident and breaks with the GNU assembler as well as global_asm!() for
     // the LLVM backend.
-    if template.len() == 1
-        && template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string())
-    {
+    if template.len() == 1 && template[0] == InlineAsmTemplatePiece::String("int $$0x29".into()) {
         fx.bcx.ins().trap(TrapCode::User(1));
         return;
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index e1896138e48..a20faa2cad3 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -40,7 +40,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
                     shl rdx, 32
                     or rax, rdx
                     "
-                    .to_string(),
+                    .into(),
                 )],
                 &[
                     CInlineAsmOperand::In {
@@ -471,7 +471,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             // into 0x80000000 for which Cranelift doesn't have a native instruction.
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(format!("cvtps2dq xmm0, xmm0"))],
+                &[InlineAsmTemplatePiece::String("cvtps2dq xmm0, xmm0".into())],
                 &[CInlineAsmOperand::InOut {
                     reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
                     _late: true,
@@ -875,7 +875,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(asm.to_string())],
+                &[InlineAsmTemplatePiece::String(asm.into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
@@ -914,7 +914,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(format!("pcmpestri xmm0, xmm1, {imm8}"))],
+                &[InlineAsmTemplatePiece::String(format!("pcmpestri xmm0, xmm1, {imm8}").into())],
                 &[
                     CInlineAsmOperand::In {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -967,7 +967,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(format!("pcmpestrm xmm0, xmm1, {imm8}"))],
+                &[InlineAsmTemplatePiece::String(format!("pcmpestrm xmm0, xmm1, {imm8}").into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -1015,7 +1015,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(format!("pclmulqdq xmm0, xmm1, {imm8}"))],
+                &[InlineAsmTemplatePiece::String(format!("pclmulqdq xmm0, xmm1, {imm8}").into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -1052,7 +1052,9 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(format!("aeskeygenassist xmm0, xmm0, {imm8}"))],
+                &[InlineAsmTemplatePiece::String(
+                    format!("aeskeygenassist xmm0, xmm0, {imm8}").into(),
+                )],
                 &[CInlineAsmOperand::InOut {
                     reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
                     _late: true,
@@ -1071,7 +1073,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("aesimc xmm0, xmm0".to_string())],
+                &[InlineAsmTemplatePiece::String("aesimc xmm0, xmm0".into())],
                 &[CInlineAsmOperand::InOut {
                     reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
                     _late: true,
@@ -1091,7 +1093,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("aesenc xmm0, xmm1".to_string())],
+                &[InlineAsmTemplatePiece::String("aesenc xmm0, xmm1".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -1117,7 +1119,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("aesenclast xmm0, xmm1".to_string())],
+                &[InlineAsmTemplatePiece::String("aesenclast xmm0, xmm1".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -1143,7 +1145,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("aesdec xmm0, xmm1".to_string())],
+                &[InlineAsmTemplatePiece::String("aesdec xmm0, xmm1".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -1169,7 +1171,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("aesdeclast xmm0, xmm1".to_string())],
+                &[InlineAsmTemplatePiece::String("aesdeclast xmm0, xmm1".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
@@ -1207,7 +1209,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String(format!("sha1rnds4 xmm1, xmm2, {func}"))],
+                &[InlineAsmTemplatePiece::String(format!("sha1rnds4 xmm1, xmm2, {func}").into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1233,7 +1235,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("sha1msg1 xmm1, xmm2".to_string())],
+                &[InlineAsmTemplatePiece::String("sha1msg1 xmm1, xmm2".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1259,7 +1261,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("sha1msg2 xmm1, xmm2".to_string())],
+                &[InlineAsmTemplatePiece::String("sha1msg2 xmm1, xmm2".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1285,7 +1287,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("sha1nexte xmm1, xmm2".to_string())],
+                &[InlineAsmTemplatePiece::String("sha1nexte xmm1, xmm2".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1312,7 +1314,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("sha256rnds2 xmm1, xmm2".to_string())],
+                &[InlineAsmTemplatePiece::String("sha256rnds2 xmm1, xmm2".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1343,7 +1345,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("sha256msg1 xmm1, xmm2".to_string())],
+                &[InlineAsmTemplatePiece::String("sha256msg1 xmm1, xmm2".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1369,7 +1371,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("sha256msg2 xmm1, xmm2".to_string())],
+                &[InlineAsmTemplatePiece::String("sha256msg2 xmm1, xmm2".into())],
                 &[
                     CInlineAsmOperand::InOut {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
@@ -1435,7 +1437,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             let edx_place = res_place.place_field(fx, FieldIdx::new(1));
             codegen_inline_asm_inner(
                 fx,
-                &[InlineAsmTemplatePiece::String("rdtsc".to_string())],
+                &[InlineAsmTemplatePiece::String("rdtsc".into())],
                 &[
                     CInlineAsmOperand::Out {
                         reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 164d1681a36..80aa2018c81 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -330,7 +330,7 @@ impl<'ll> CodegenCx<'ll, '_> {
 
             // If this assertion triggers, there's something wrong with commandline
             // argument validation.
-            debug_assert!(
+            assert!(
                 !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
                     && self.tcx.sess.target.is_like_windows
                     && self.tcx.sess.opts.cg.prefer_dynamic)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 851a4c42e99..364c35f3107 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -170,7 +170,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
 ) -> DINodeCreationResult<'ll> {
     // The debuginfo generated by this function is only valid if `ptr_type` is really just
     // a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
-    debug_assert_eq!(
+    assert_eq!(
         cx.size_and_align_of(ptr_type),
         cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
     );
@@ -185,7 +185,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
     match fat_pointer_kind(cx, pointee_type) {
         None => {
             // This is a thin pointer. Create a regular pointer type and give it the correct name.
-            debug_assert_eq!(
+            assert_eq!(
                 (data_layout.pointer_size, data_layout.pointer_align.abi),
                 cx.size_and_align_of(ptr_type),
                 "ptr_type={ptr_type}, pointee_type={pointee_type}",
@@ -240,8 +240,8 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                         FatPtrKind::Slice => ("data_ptr", "length"),
                     };
 
-                    debug_assert_eq!(abi::FAT_PTR_ADDR, 0);
-                    debug_assert_eq!(abi::FAT_PTR_EXTRA, 1);
+                    assert_eq!(abi::FAT_PTR_ADDR, 0);
+                    assert_eq!(abi::FAT_PTR_EXTRA, 1);
 
                     // The data pointer type is a regular, thin pointer, regardless of whether this
                     // is a slice or a trait object.
@@ -498,7 +498,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
                     }
                 };
 
-            debug_assert_eq!(di_node_for_uid as *const _, di_node as *const _);
+            assert_eq!(di_node_for_uid as *const _, di_node as *const _);
         } else {
             debug_context(cx).type_map.insert(unique_type_id, di_node);
         }
@@ -1060,7 +1060,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
     let ty::Adt(adt_def, _) = struct_type.kind() else {
         bug!("build_struct_type_di_node() called with non-struct-type: {:?}", struct_type);
     };
-    debug_assert!(adt_def.is_struct());
+    assert!(adt_def.is_struct());
     let containing_scope = get_namespace_for_item(cx, adt_def.did());
     let struct_type_and_layout = cx.layout_of(struct_type);
     let variant_def = adt_def.non_enum_variant();
@@ -1130,7 +1130,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
         }
     };
 
-    debug_assert!(
+    assert!(
         up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
     );
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index 12f98eef97d..cf7dddce84f 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -204,7 +204,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
     let enum_type_and_layout = cx.layout_of(enum_type);
     let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
 
-    debug_assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
+    assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
 
     type_map::build_type_with_children(
         cx,
@@ -279,7 +279,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
     let coroutine_type_and_layout = cx.layout_of(coroutine_type);
     let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
 
-    debug_assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
+    assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
 
     type_map::build_type_with_children(
         cx,
@@ -517,7 +517,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
                     if is_128_bits {
                         DiscrKind::Exact128(discr_val)
                     } else {
-                        debug_assert_eq!(discr_val, discr_val as u64 as u128);
+                        assert_eq!(discr_val, discr_val as u64 as u128);
                         DiscrKind::Exact(discr_val as u64)
                     }
                 }
@@ -526,8 +526,8 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
                     if is_128_bits {
                         DiscrKind::Range128(min, max)
                     } else {
-                        debug_assert_eq!(min, min as u64 as u128);
-                        debug_assert_eq!(max, max as u64 as u128);
+                        assert_eq!(min, min as u64 as u128);
+                        assert_eq!(max, max as u64 as u128);
                         DiscrKind::Range(min as u64, max as u64)
                     }
                 }
@@ -815,7 +815,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
         }
     }));
 
-    debug_assert_eq!(
+    assert_eq!(
         cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
         cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout))
     );
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 2b00bb14593..96be1900ab2 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -106,7 +106,7 @@ fn tag_base_type<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     enum_type_and_layout: TyAndLayout<'tcx>,
 ) -> Ty<'tcx> {
-    debug_assert!(match enum_type_and_layout.ty.kind() {
+    assert!(match enum_type_and_layout.ty.kind() {
         ty::Coroutine(..) => true,
         ty::Adt(adt_def, _) => adt_def.is_enum(),
         _ => false,
@@ -251,7 +251,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
     variant_layout: TyAndLayout<'tcx>,
     di_flags: DIFlags,
 ) -> &'ll DIType {
-    debug_assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
+    assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
 
     type_map::build_type_with_children(
         cx,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index 115d5187eaf..63a9ce2fdf9 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -65,7 +65,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
 
     let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
 
-    debug_assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
+    assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
 
     type_map::build_type_with_children(
         cx,
@@ -142,7 +142,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
     let containing_scope = get_namespace_for_item(cx, coroutine_def_id);
     let coroutine_type_and_layout = cx.layout_of(coroutine_type);
 
-    debug_assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
+    assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
 
     let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index e521d5e259c..17931911f87 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -36,7 +36,7 @@ mod private {
 
 /// A unique identifier for anything that we create a debuginfo node for.
 /// The types it contains are expected to already be normalized (which
-/// is debug_asserted in the constructors).
+/// is asserted in the constructors).
 ///
 /// Note that there are some things that only show up in debuginfo, like
 /// the separate type descriptions for each enum variant. These get an ID
@@ -58,12 +58,12 @@ pub(super) enum UniqueTypeId<'tcx> {
 
 impl<'tcx> UniqueTypeId<'tcx> {
     pub fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self {
-        debug_assert_eq!(t, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t));
+        assert_eq!(t, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t));
         UniqueTypeId::Ty(t, private::HiddenZst)
     }
 
     pub fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self {
-        debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
         UniqueTypeId::VariantPart(enum_ty, private::HiddenZst)
     }
 
@@ -72,7 +72,7 @@ impl<'tcx> UniqueTypeId<'tcx> {
         enum_ty: Ty<'tcx>,
         variant_idx: VariantIdx,
     ) -> Self {
-        debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
         UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst)
     }
 
@@ -81,7 +81,7 @@ impl<'tcx> UniqueTypeId<'tcx> {
         enum_ty: Ty<'tcx>,
         variant_idx: VariantIdx,
     ) -> Self {
-        debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
+        assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty));
         UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst)
     }
 
@@ -90,11 +90,8 @@ impl<'tcx> UniqueTypeId<'tcx> {
         self_type: Ty<'tcx>,
         implemented_trait: Option<PolyExistentialTraitRef<'tcx>>,
     ) -> Self {
-        debug_assert_eq!(
-            self_type,
-            tcx.normalize_erasing_regions(ParamEnv::reveal_all(), self_type)
-        );
-        debug_assert_eq!(
+        assert_eq!(self_type, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), self_type));
+        assert_eq!(
             implemented_trait,
             tcx.normalize_erasing_regions(ParamEnv::reveal_all(), implemented_trait)
         );
@@ -252,10 +249,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
     members: impl FnOnce(&CodegenCx<'ll, 'tcx>, &'ll DIType) -> SmallVec<&'ll DIType>,
     generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<&'ll DIType>,
 ) -> DINodeCreationResult<'ll> {
-    debug_assert_eq!(
-        debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id),
-        None
-    );
+    assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);
 
     debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata);
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 155e7a89fd8..9bd2ccceadf 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -81,7 +81,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
         ty::Dynamic(..) => Some(FatPtrKind::Dyn),
         ty::Foreign(_) => {
             // Assert that pointers to foreign types really are thin:
-            debug_assert_eq!(
+            assert_eq!(
                 cx.size_of(Ty::new_imm_ptr(cx.tcx, pointee_tail_ty)),
                 cx.size_of(Ty::new_imm_ptr(cx.tcx, cx.tcx.types.u8))
             );
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index ae46200d3f5..3beda28ac1f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -305,7 +305,6 @@ pub enum TypeKind {
     Pointer = 12,
     Vector = 13,
     Metadata = 14,
-    X86_MMX = 15,
     Token = 16,
     ScalableVector = 17,
     BFloat = 18,
@@ -330,7 +329,6 @@ impl TypeKind {
             TypeKind::Pointer => rustc_codegen_ssa::common::TypeKind::Pointer,
             TypeKind::Vector => rustc_codegen_ssa::common::TypeKind::Vector,
             TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata,
-            TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX,
             TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token,
             TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector,
             TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat,
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 6abe4fa1c38..b7ad09b055a 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -352,7 +352,7 @@ fn exported_symbols_provider_local(
                 }
                 MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => {
                     // A little sanity-check
-                    debug_assert_eq!(
+                    assert_eq!(
                         args.non_erasable_generics(tcx, def_id).next(),
                         Some(GenericArgKind::Type(ty))
                     );
@@ -370,7 +370,7 @@ fn exported_symbols_provider_local(
                     args,
                 }) => {
                     // A little sanity-check
-                    debug_assert_eq!(
+                    assert_eq!(
                         args.non_erasable_generics(tcx, def_id).next(),
                         Some(GenericArgKind::Type(ty))
                     );
@@ -462,7 +462,7 @@ fn upstream_monomorphizations_for_provider(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> Option<&UnordMap<GenericArgsRef<'_>, CrateNum>> {
-    debug_assert!(!def_id.is_local());
+    assert!(!def_id.is_local());
     tcx.upstream_monomorphizations(()).get(&def_id)
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 0e48eee3dd5..56e94529bc1 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1512,7 +1512,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
                             // We reduce the `running` counter by one. The
                             // `tokens.truncate()` below will take care of
                             // giving the Token back.
-                            debug_assert!(running_with_own_token > 0);
+                            assert!(running_with_own_token > 0);
                             running_with_own_token -= 1;
                             main_thread_state = MainThreadState::Lending;
                         }
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 27b0f127e92..ea2fd482e1f 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -91,7 +91,6 @@ pub enum TypeKind {
     Pointer,
     Vector,
     Metadata,
-    X86_MMX,
     Token,
     ScalableVector,
     BFloat,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index c4e5c858240..6a6d47fcbba 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -459,7 +459,7 @@ fn push_debuginfo_type_name<'tcx>(
         output: &mut String,
         visited: &mut FxHashSet<Ty<'tcx>>,
     ) {
-        debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
+        assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
         output.push_str("enum2$<");
         push_inner(output, visited);
         push_close_angle_bracket(true, output);
@@ -660,7 +660,7 @@ fn push_generic_params_internal<'tcx>(
     output: &mut String,
     visited: &mut FxHashSet<Ty<'tcx>>,
 ) -> bool {
-    debug_assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args));
+    assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args));
     let mut args = args.non_erasable_generics(tcx, def_id).peekable();
     if args.peek().is_none() {
         return false;
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index c9c8f02c491..9cb8b719b12 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -84,7 +84,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         }
         if is_cleanupret {
             // Cross-funclet jump - need a trampoline
-            debug_assert!(base::wants_new_eh_instructions(fx.cx.tcx().sess));
+            assert!(base::wants_new_eh_instructions(fx.cx.tcx().sess));
             debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target);
             let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target);
             let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name);
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 6b89636b654..82ed5610d9e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -194,7 +194,7 @@ fn calculate_debuginfo_offset<
             }
             _ => {
                 // Sanity check for `can_use_in_debuginfo`.
-                debug_assert!(!elem.can_use_in_debuginfo());
+                assert!(!elem.can_use_in_debuginfo());
                 bug!("unsupported var debuginfo projection `{:?}`", projection)
             }
         }
@@ -502,7 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                 let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
                     calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
-                debug_assert!(indirect_offsets.is_empty());
+                assert!(indirect_offsets.is_empty());
 
                 if fragment_layout.size == Size::ZERO {
                     // Fragment is a ZST, so does not represent anything. Avoid generating anything
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index cc0e9139650..e08d7a3e826 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -565,7 +565,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 for elem in place_ref.projection.iter() {
                     match elem {
                         mir::ProjectionElem::Field(ref f, _) => {
-                            debug_assert!(
+                            assert!(
                                 !o.layout.ty.is_any_ptr(),
                                 "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
                                  but tried to access field {f:?} of pointer {o:?}",
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 97d5bb83128..4394ffb7a1c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -55,7 +55,7 @@ impl<V: CodegenObject> PlaceValue<V> {
 
     /// Creates a `PlaceRef` to this location with the given type.
     pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
-        debug_assert!(
+        assert!(
             layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
             "Had pointer metadata {:?} for sized type {layout:?}",
             self.llextra,
@@ -488,7 +488,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             cg_base = match *elem {
                 mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
                 mir::ProjectionElem::Field(ref field, _) => {
-                    debug_assert!(
+                    assert!(
                         !cg_base.layout.ty.is_any_ptr(),
                         "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
                          but tried to access field {field:?} of pointer {cg_base:?}",
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index f9e928a84a7..0cd3e60b0cc 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -168,8 +168,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         dst: PlaceRef<'tcx, Bx::Value>,
     ) {
         // The MIR validator enforces no unsized transmutes.
-        debug_assert!(src.layout.is_sized());
-        debug_assert!(dst.layout.is_sized());
+        assert!(src.layout.is_sized());
+        assert!(dst.layout.is_sized());
 
         if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) {
             val.store(bx, dst);
@@ -223,8 +223,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         match operand.val {
             OperandValue::Ref(source_place_val) => {
-                debug_assert_eq!(source_place_val.llextra, None);
-                debug_assert!(matches!(operand_kind, OperandValueKind::Ref));
+                assert_eq!(source_place_val.llextra, None);
+                assert!(matches!(operand_kind, OperandValueKind::Ref));
                 Some(bx.load_operand(source_place_val.with_type(cast)).val)
             }
             OperandValue::ZeroSized => {
@@ -295,7 +295,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         to_scalar: abi::Scalar,
         to_backend_ty: Bx::Type,
     ) -> Bx::Value {
-        debug_assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
+        assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
 
         use abi::Primitive::*;
         imm = bx.from_immediate(imm);
@@ -639,9 +639,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         (OperandValue::Immediate(llval), operand.layout)
                     }
                     mir::UnOp::PtrMetadata => {
-                        debug_assert!(
-                            operand.layout.ty.is_unsafe_ptr() || operand.layout.ty.is_ref(),
-                        );
+                        assert!(operand.layout.ty.is_unsafe_ptr() || operand.layout.ty.is_ref(),);
                         let (_, meta) = operand.val.pointer_parts();
                         assert_eq!(operand.layout.fields.count() > 1, meta.is_some());
                         if let Some(meta) = meta {
@@ -651,7 +649,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                     }
                 };
-                debug_assert!(
+                assert!(
                     val.is_expected_variant_for_type(self.cx, layout),
                     "Made wrong variant {val:?} for type {layout:?}",
                 );
@@ -742,7 +740,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         bug!("Field {field_idx:?} is {p:?} making {layout:?}");
                     });
                     let scalars = self.value_kind(op.layout).scalars().unwrap();
-                    debug_assert_eq!(values.len(), scalars.len());
+                    assert_eq!(values.len(), scalars.len());
                     inputs.extend(values);
                     input_scalars.extend(scalars);
                 }
@@ -760,7 +758,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 );
 
                 let val = OperandValue::from_immediates(inputs);
-                debug_assert!(
+                assert!(
                     val.is_expected_variant_for_type(self.cx, layout),
                     "Made wrong variant {val:?} for type {layout:?}",
                 );
@@ -805,7 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let val = cg_place.val.address();
 
         let ty = cg_place.layout.ty;
-        debug_assert!(
+        assert!(
             if bx.cx().type_has_metadata(ty) {
                 matches!(val, OperandValue::Pair(..))
             } else {
@@ -927,7 +925,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
             mir::BinOp::Cmp => {
                 use std::cmp::Ordering;
-                debug_assert!(!is_float);
+                assert!(!is_float);
                 let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
                 if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
                     // FIXME: This actually generates tighter assembly, and is a classic trick
@@ -1111,7 +1109,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         if layout.is_zst() {
             OperandValueKind::ZeroSized
         } else if self.cx.is_backend_immediate(layout) {
-            debug_assert!(!self.cx.is_backend_scalar_pair(layout));
+            assert!(!self.cx.is_backend_scalar_pair(layout));
             OperandValueKind::Immediate(match layout.abi {
                 abi::Abi::Scalar(s) => s,
                 abi::Abi::Vector { element, .. } => element,
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 2f0daefa46a..42980d9ebd2 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -165,7 +165,7 @@ pub trait BuilderMethods<'a, 'tcx>:
         size: Size,
     ) -> Self::Value;
     fn load_from_place(&mut self, ty: Self::Type, place: PlaceValue<Self::Value>) -> Self::Value {
-        debug_assert_eq!(place.llextra, None);
+        assert_eq!(place.llextra, None);
         self.load(ty, place.llval, place.align)
     }
     fn load_operand(&mut self, place: PlaceRef<'tcx, Self::Value>)
@@ -184,7 +184,7 @@ pub trait BuilderMethods<'a, 'tcx>:
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
     fn store_to_place(&mut self, val: Self::Value, place: PlaceValue<Self::Value>) -> Self::Value {
-        debug_assert_eq!(place.llextra, None);
+        assert_eq!(place.llextra, None);
         self.store(val, place.llval, place.align)
     }
     fn store_with_flags(
@@ -200,7 +200,7 @@ pub trait BuilderMethods<'a, 'tcx>:
         place: PlaceValue<Self::Value>,
         flags: MemFlags,
     ) -> Self::Value {
-        debug_assert_eq!(place.llextra, None);
+        assert_eq!(place.llextra, None);
         self.store_with_flags(val, place.llval, place.align, flags)
     }
     fn atomic_store(
@@ -320,9 +320,9 @@ pub trait BuilderMethods<'a, 'tcx>:
         layout: TyAndLayout<'tcx>,
         flags: MemFlags,
     ) {
-        debug_assert!(layout.is_sized(), "cannot typed-copy an unsigned type");
-        debug_assert!(src.llextra.is_none(), "cannot directly copy from unsized values");
-        debug_assert!(dst.llextra.is_none(), "cannot directly copy into unsized values");
+        assert!(layout.is_sized(), "cannot typed-copy an unsigned type");
+        assert!(src.llextra.is_none(), "cannot directly copy from unsized values");
+        assert!(dst.llextra.is_none(), "cannot directly copy into unsized values");
         if flags.contains(MemFlags::NONTEMPORAL) {
             // HACK(nox): This is inefficient but there is no nontemporal memcpy.
             let ty = self.backend_type(layout);
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 4da7e233889..3dc3e6c8833 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -34,6 +34,8 @@ use super::{
     Pointer, Projectable, Scalar, ValueVisitor,
 };
 
+// for the validation errors
+#[rustfmt::skip]
 use super::InterpError::UndefinedBehavior as Ub;
 use super::InterpError::Unsupported as Unsup;
 use super::UndefinedBehaviorInfo::*;
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index cc114fdcd8c..2fff9f2de50 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -26,7 +26,6 @@ serde_json = "1.0.59"
 termcolor = "1.2.0"
 termize = "0.1.1"
 tracing = "0.1"
-unicode-width = "0.1.4"
 # tidy-alphabetical-end
 
 [target.'cfg(windows)'.dependencies.windows]
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index aa47ca16676..58220c65490 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -8,7 +8,7 @@
 //! The output types are defined in `rustc_session::config::ErrorOutputType`.
 
 use rustc_span::source_map::SourceMap;
-use rustc_span::{FileLines, FileName, SourceFile, Span};
+use rustc_span::{char_width, FileLines, FileName, SourceFile, Span};
 
 use crate::snippet::{
     Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
@@ -677,10 +677,7 @@ impl HumanEmitter {
             .skip(left)
             .take_while(|ch| {
                 // Make sure that the trimming on the right will fall within the terminal width.
-                // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char`
-                // is. For now, just accept that sometimes the code line will be longer than
-                // desired.
-                let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1);
+                let next = char_width(*ch);
                 if taken + next > right - left {
                     return false;
                 }
@@ -742,11 +739,7 @@ impl HumanEmitter {
         let left = margin.left(source_string.len());
 
         // Account for unicode characters of width !=0 that were removed.
-        let left = source_string
-            .chars()
-            .take(left)
-            .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
-            .sum();
+        let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum();
 
         self.draw_line(
             buffer,
@@ -2039,7 +2032,7 @@ impl HumanEmitter {
                     let sub_len: usize =
                         if is_whitespace_addition { &part.snippet } else { part.snippet.trim() }
                             .chars()
-                            .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
+                            .map(|ch| char_width(ch))
                             .sum();
 
                     let offset: isize = offsets
@@ -2076,11 +2069,8 @@ impl HumanEmitter {
                     }
 
                     // length of the code after substitution
-                    let full_sub_len = part
-                        .snippet
-                        .chars()
-                        .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
-                        .sum::<usize>() as isize;
+                    let full_sub_len =
+                        part.snippet.chars().map(|ch| char_width(ch)).sum::<usize>() as isize;
 
                     // length of the code to be substituted
                     let snippet_len = span_end_pos as isize - span_start_pos as isize;
@@ -2568,18 +2558,53 @@ fn num_decimal_digits(num: usize) -> usize {
 }
 
 // We replace some characters so the CLI output is always consistent and underlines aligned.
+// Keep the following list in sync with `rustc_span::char_width`.
 const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
-    ('\t', "    "),   // We do our own tab replacement
+    ('\t', "    "),    // We do our own tab replacement
     ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
-    ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
-    ('\u{202B}', ""), // supported across CLIs and can cause confusion due to the bytes on disk
-    ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
-    ('\u{202E}', ""),
-    ('\u{2066}', ""),
-    ('\u{2067}', ""),
-    ('\u{2068}', ""),
-    ('\u{202C}', ""),
-    ('\u{2069}', ""),
+    ('\u{202A}', "�"), // The following unicode text flow control characters are inconsistently
+    ('\u{202B}', "�"), // supported across CLIs and can cause confusion due to the bytes on disk
+    ('\u{202D}', "�"), // not corresponding to the visible source code, so we replace them always.
+    ('\u{202E}', "�"),
+    ('\u{2066}', "�"),
+    ('\u{2067}', "�"),
+    ('\u{2068}', "�"),
+    ('\u{202C}', "�"),
+    ('\u{2069}', "�"),
+    // In terminals without Unicode support the following will be garbled, but in *all* terminals
+    // the underlying codepoint will be as well. We could gate this replacement behind a "unicode
+    // support" gate.
+    ('\u{0000}', "␀"),
+    ('\u{0001}', "␁"),
+    ('\u{0002}', "␂"),
+    ('\u{0003}', "␃"),
+    ('\u{0004}', "␄"),
+    ('\u{0005}', "␅"),
+    ('\u{0006}', "␆"),
+    ('\u{0007}', "␇"),
+    ('\u{0008}', "␈"),
+    ('\u{000B}', "␋"),
+    ('\u{000C}', "␌"),
+    ('\u{000D}', "␍"),
+    ('\u{000E}', "␎"),
+    ('\u{000F}', "␏"),
+    ('\u{0010}', "␐"),
+    ('\u{0011}', "␑"),
+    ('\u{0012}', "␒"),
+    ('\u{0013}', "␓"),
+    ('\u{0014}', "␔"),
+    ('\u{0015}', "␕"),
+    ('\u{0016}', "␖"),
+    ('\u{0017}', "␗"),
+    ('\u{0018}', "␘"),
+    ('\u{0019}', "␙"),
+    ('\u{001A}', "␚"),
+    ('\u{001B}', "␛"),
+    ('\u{001C}', "␜"),
+    ('\u{001D}', "␝"),
+    ('\u{001E}', "␞"),
+    ('\u{001F}', "␟"),
+    ('\u{007F}', "␡"),
 ];
 
 fn normalize_whitespace(str: &str) -> String {
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 19371448025..06ec01484a4 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -6,10 +6,10 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
-use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::util::CheckRegions;
-use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{GenericArgsRef, Ty};
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
@@ -115,8 +115,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     Err(err.emit())
 }
 
-/// Confirms that every predicate imposed by dtor_predicates is
-/// implied by assuming the predicates attached to self_type_did.
+/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
+/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
+/// implied by the ADT being well formed.
 fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     tcx: TyCtxt<'tcx>,
     drop_impl_def_id: LocalDefId,
@@ -126,6 +127,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     let infcx = tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
+    let impl_span = tcx.def_span(drop_impl_def_id.to_def_id());
+
     // Take the param-env of the adt and instantiate the args that show up in
     // the implementation's self type. This gives us the assumptions that the
     // self ty of the implementation is allowed to know just from it being a
@@ -135,14 +138,27 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     // We don't need to normalize this param-env or anything, since we're only
     // instantiating it with free params, so no additional param-env normalization
     // can occur on top of what has been done in the param_env query itself.
-    let param_env =
+    //
+    // Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we
+    // could instead use identity args for the adt. Unfortunately this would cause any errors to
+    // reference the params from the ADT instead of from the impl which is bad UX. To resolve
+    // this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
+    let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
+    let adt_env =
         ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
 
-    for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
+    let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id());
+    let fresh_adt_ty =
+        tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
+
+    ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
+        .unwrap();
+
+    for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) {
         let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
-        let pred = ocx.normalize(&normalize_cause, param_env, pred);
+        let pred = ocx.normalize(&normalize_cause, adt_env, clause);
         let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl);
-        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
+        ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
     }
 
     // All of the custom error reporting logic is to preserve parity with the old
@@ -176,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
         return Err(guar.unwrap());
     }
 
-    let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
+    let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(adt_env));
     if !errors.is_empty() {
         let mut guar = None;
         for error in errors {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index db5eba0d9eb..a982b84e755 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1298,35 +1298,7 @@ impl<'a> State<'a> {
             AsmArg::Options(opts) => {
                 s.word("options");
                 s.popen();
-                let mut options = vec![];
-                if opts.contains(ast::InlineAsmOptions::PURE) {
-                    options.push("pure");
-                }
-                if opts.contains(ast::InlineAsmOptions::NOMEM) {
-                    options.push("nomem");
-                }
-                if opts.contains(ast::InlineAsmOptions::READONLY) {
-                    options.push("readonly");
-                }
-                if opts.contains(ast::InlineAsmOptions::PRESERVES_FLAGS) {
-                    options.push("preserves_flags");
-                }
-                if opts.contains(ast::InlineAsmOptions::NORETURN) {
-                    options.push("noreturn");
-                }
-                if opts.contains(ast::InlineAsmOptions::NOSTACK) {
-                    options.push("nostack");
-                }
-                if opts.contains(ast::InlineAsmOptions::ATT_SYNTAX) {
-                    options.push("att_syntax");
-                }
-                if opts.contains(ast::InlineAsmOptions::RAW) {
-                    options.push("raw");
-                }
-                if opts.contains(ast::InlineAsmOptions::MAY_UNWIND) {
-                    options.push("may_unwind");
-                }
-                s.commasep(Inconsistent, &options, |s, &opt| {
+                s.commasep(Inconsistent, &opts.human_readable_names(), |s, &opt| {
                     s.word(opt);
                 });
                 s.pclose();
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7d7b97e2eb1..a87b3c2c135 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -5,6 +5,11 @@ lint_ambiguous_glob_reexport = ambiguous glob re-exports
     .label_first_reexport = the name `{$name}` in the {$namespace} namespace is first re-exported here
     .label_duplicate_reexport = but the name `{$name}` in the {$namespace} namespace is also re-exported here
 
+lint_ambiguous_negative_literals = `-` has lower precedence than method calls, which might be unexpected
+    .example = e.g. `-4.abs()` equals `-4`; while `(-4).abs()` equals `4`
+    .negative_literal = add parentheses around the `-` and the literal to call the method on a negative literal
+    .current_behavior = add parentheses around the literal and the method call to keep the current behavior
+
 lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
     .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
     .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index fc073233d97..7c44d16169e 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -73,6 +73,7 @@ mod noop_method_call;
 mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
+mod precedence;
 mod ptr_nulls;
 mod redundant_semicolon;
 mod reference_casting;
@@ -111,6 +112,7 @@ use nonstandard_style::*;
 use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
+use precedence::*;
 use ptr_nulls::*;
 use redundant_semicolon::*;
 use reference_casting::*;
@@ -120,6 +122,7 @@ use types::*;
 use unit_bindings::*;
 use unused::*;
 
+#[rustfmt::skip]
 pub use builtin::{MissingDoc, SoftLints};
 pub use context::{CheckLintNameResult, FindLintError, LintStore};
 pub use context::{EarlyContext, LateContext, LintContext};
@@ -174,6 +177,7 @@ early_lint_methods!(
             RedundantSemicolons: RedundantSemicolons,
             UnusedDocComment: UnusedDocComment,
             Expr2024: Expr2024,
+            Precedence: Precedence,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 6c5f366727f..1f0954c6e9f 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1499,6 +1499,35 @@ pub struct NonLocalDefinitionsCargoUpdateNote {
     pub crate_name: Symbol,
 }
 
+// precedence.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_ambiguous_negative_literals)]
+#[note(lint_example)]
+pub struct AmbiguousNegativeLiteralsDiag {
+    #[subdiagnostic]
+    pub negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion,
+    #[subdiagnostic]
+    pub current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_negative_literal, applicability = "maybe-incorrect")]
+pub struct AmbiguousNegativeLiteralsNegativeLiteralSuggestion {
+    #[suggestion_part(code = "(")]
+    pub start_span: Span,
+    #[suggestion_part(code = ")")]
+    pub end_span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_current_behavior, applicability = "maybe-incorrect")]
+pub struct AmbiguousNegativeLiteralsCurrentBehaviorSuggestion {
+    #[suggestion_part(code = "(")]
+    pub start_span: Span,
+    #[suggestion_part(code = ")")]
+    pub end_span: Span,
+}
+
 // pass_by_value.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_pass_by_value)]
diff --git a/compiler/rustc_lint/src/precedence.rs b/compiler/rustc_lint/src/precedence.rs
new file mode 100644
index 00000000000..eb2ba397277
--- /dev/null
+++ b/compiler/rustc_lint/src/precedence.rs
@@ -0,0 +1,70 @@
+use rustc_ast::token::LitKind;
+use rustc_ast::{Expr, ExprKind, MethodCall, UnOp};
+use rustc_session::{declare_lint, declare_lint_pass};
+
+use crate::lints::{
+    AmbiguousNegativeLiteralsCurrentBehaviorSuggestion, AmbiguousNegativeLiteralsDiag,
+    AmbiguousNegativeLiteralsNegativeLiteralSuggestion,
+};
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+
+declare_lint! {
+    /// The `ambiguous_negative_literals` lint checks for cases that are
+    /// confusing between a negative literal and a negation that's not part
+    /// of the literal.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// -1i32.abs(); // equals -1, while `(-1i32).abs()` equals 1
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Method calls take precedence over unary precedence. Setting the
+    /// precedence explicitly makes the code clearer and avoid potential bugs.
+    pub AMBIGUOUS_NEGATIVE_LITERALS,
+    Deny,
+    "ambiguous negative literals operations",
+    report_in_external_macro
+}
+
+declare_lint_pass!(Precedence => [AMBIGUOUS_NEGATIVE_LITERALS]);
+
+impl EarlyLintPass for Precedence {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind else {
+            return;
+        };
+
+        let mut arg = operand;
+        let mut at_least_one = false;
+        while let ExprKind::MethodCall(box MethodCall { receiver, .. }) = &arg.kind {
+            at_least_one = true;
+            arg = receiver;
+        }
+
+        if at_least_one
+            && let ExprKind::Lit(lit) = &arg.kind
+            && let LitKind::Integer | LitKind::Float = &lit.kind
+        {
+            cx.emit_span_lint(
+                AMBIGUOUS_NEGATIVE_LITERALS,
+                expr.span,
+                AmbiguousNegativeLiteralsDiag {
+                    negative_literal: AmbiguousNegativeLiteralsNegativeLiteralSuggestion {
+                        start_span: expr.span.shrink_to_lo(),
+                        end_span: arg.span.shrink_to_hi(),
+                    },
+                    current_behavior: AmbiguousNegativeLiteralsCurrentBehaviorSuggestion {
+                        start_span: operand.span.shrink_to_lo(),
+                        end_span: operand.span.shrink_to_hi(),
+                    },
+                },
+            );
+        }
+    }
+}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 14757b27a37..4cdd8af1008 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1419,8 +1419,6 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMPointerTypeKind;
   case Type::FixedVectorTyID:
     return LLVMVectorTypeKind;
-  case Type::X86_MMXTyID:
-    return LLVMX86_MMXTypeKind;
   case Type::TokenTyID:
     return LLVMTokenTypeKind;
   case Type::ScalableVectorTyID:
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e5e430bc90d..9874624ae25 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1728,7 +1728,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                     source_len,
                     lines,
                     multibyte_chars,
-                    non_narrow_chars,
                     normalized_pos,
                     stable_id,
                     ..
@@ -1780,7 +1779,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                     self.cnum,
                     lines,
                     multibyte_chars,
-                    non_narrow_chars,
                     normalized_pos,
                     source_file_index,
                 );
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 290ebde8712..69e3b703cce 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-derivative = "2.2.0"
+derive-where = "1.2.7"
 either = "1.5.0"
 field-offset = "0.3.5"
 gsgdt = "0.1.2"
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index cd8e28522ec..acf4414c4d6 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -2,6 +2,7 @@
 
 use crate::mir;
 use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt};
+use derive_where::derive_where;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::LocalDefId;
@@ -224,13 +225,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 /// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
-#[derive(derivative::Derivative)]
-#[derivative(
-    PartialOrd,
-    Ord,
-    PartialOrd = "feature_allow_slow_enum",
-    Ord = "feature_allow_slow_enum"
-)]
+#[derive_where(PartialOrd, Ord)]
 pub enum ConstraintCategory<'tcx> {
     Return(ReturnConstraint),
     Yield,
@@ -240,7 +235,7 @@ pub enum ConstraintCategory<'tcx> {
     Cast {
         /// Whether this is an unsizing cast and if yes, this contains the target type.
         /// Region variables are erased to ReErased.
-        #[derivative(PartialOrd = "ignore", Ord = "ignore")]
+        #[derive_where(skip)]
         unsize_to: Option<Ty<'tcx>>,
     },
 
@@ -250,7 +245,7 @@ pub enum ConstraintCategory<'tcx> {
     ClosureBounds,
 
     /// Contains the function type if available.
-    CallArgument(#[derivative(PartialOrd = "ignore", Ord = "ignore")] Option<Ty<'tcx>>),
+    CallArgument(#[derive_where(skip)] Option<Ty<'tcx>>),
     CopyBound,
     SizedBound,
     Assignment,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 99afb500e0b..5f13b329de4 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -3,7 +3,6 @@ use crate::thir::cx::region::Scope;
 use crate::thir::cx::Cx;
 use crate::thir::util::UserAnnotatedTyHelpers;
 use itertools::Itertools;
-use rustc_ast::LitKind;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -22,8 +21,7 @@ use rustc_middle::ty::{
     self, AdtKind, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs, UserType,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_span::source_map::Spanned;
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{sym, Span};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use tracing::{debug, info, instrument, trace};
 
@@ -899,14 +897,10 @@ impl<'tcx> Cx<'tcx> {
                 let hir_id = self.tcx.local_def_id_to_hir_id(def_id.expect_local());
                 let generics = self.tcx.generics_of(hir_id.owner);
                 let Some(&index) = generics.param_def_id_to_index.get(&def_id) else {
-                    let guar = self.tcx.dcx().has_errors().unwrap();
-                    // We already errored about a late bound const
-
-                    let lit = self
-                        .tcx
-                        .hir_arena
-                        .alloc(Spanned { span: DUMMY_SP, node: LitKind::Err(guar) });
-                    return ExprKind::Literal { lit, neg: false };
+                    span_bug!(
+                        expr.span,
+                        "Should have already errored about late bound consts: {def_id:?}"
+                    );
                 };
                 let name = self.tcx.hir().name(hir_id);
                 let param = ty::ParamConst::new(index, name);
diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml
index 79d2107b2a0..fdf44e12378 100644
--- a/compiler/rustc_next_trait_solver/Cargo.toml
+++ b/compiler/rustc_next_trait_solver/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-derivative = "2.2.0"
+derive-where = "1.2.7"
 rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_index = { path = "../rustc_index", default-features = false }
diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs
index 55f602d907b..f22ea41c512 100644
--- a/compiler/rustc_next_trait_solver/src/coherence.rs
+++ b/compiler/rustc_next_trait_solver/src/coherence.rs
@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 use std::ops::ControlFlow;
 
+use derive_where::derive_where;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
 use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
@@ -108,15 +109,13 @@ impl From<bool> for IsFirstInputType {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = "T: Debug"))]
+#[derive_where(Debug; I: Interner, T: Debug)]
 pub enum OrphanCheckErr<I: Interner, T> {
     NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>),
     UncoveredTyParams(UncoveredTyParams<I, T>),
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = "T: Debug"))]
+#[derive_where(Debug; I: Interner, T: Debug)]
 pub struct UncoveredTyParams<I: Interner, T> {
     pub uncovered: T,
     pub local_ty: Option<I::Ty>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 01dde9ca587..f74597fcb39 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -2,6 +2,7 @@
 
 pub(super) mod structural_traits;
 
+use derive_where::derive_where;
 use rustc_type_ir::elaborate;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::inherent::*;
@@ -21,8 +22,7 @@ use crate::solve::{
 ///
 /// It consists of both the `source`, which describes how that goal would be proven,
 /// and the `result` when using the given `source`.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""))]
+#[derive_where(Clone, Debug; I: Interner)]
 pub(super) struct Candidate<I: Interner> {
     pub(super) source: CandidateSource<I>,
     pub(super) result: CanonicalResponse<I>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 7df14e81ab5..770ac9a929e 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -1,6 +1,7 @@
 //! Code which is used by built-in goals that match "structurally", such a auto
 //! traits, `Copy`/`Clone`.
 
+use derive_where::derive_where;
 use rustc_ast_ir::{Movability, Mutability};
 use rustc_type_ir::data_structures::HashMap;
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -384,8 +385,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
 
 /// Relevant types for an async callable, including its inputs, output,
 /// and the return type you get from awaiting the output.
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Debug(bound = ""))]
+#[derive_where(Clone, Copy, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub(in crate::solve) struct AsyncCallableRelevantTypes<I: Interner> {
     pub tupled_inputs_ty: I::Ty,
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index c23bc8f09ad..e328284c001 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -1,5 +1,6 @@
 use std::ops::ControlFlow;
 
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir::data_structures::ensure_sufficient_stack;
@@ -87,8 +88,7 @@ where
     pub(super) inspect: ProofTreeBuilder<D>,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))]
+#[derive_where(Clone, Debug, Default; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 // FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate.
diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
index 3e266ddac71..36e13cc97d6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
@@ -7,6 +7,7 @@
 use std::marker::PhantomData;
 use std::mem;
 
+use derive_where::derive_where;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::{self as ty, search_graph, Interner};
 
@@ -51,8 +52,7 @@ where
 /// in the code, only one or two variants are actually possible.
 ///
 /// We simply ICE in case that assumption is broken.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""))]
+#[derive_where(Debug; I: Interner)]
 enum DebugSolver<I: Interner> {
     Root,
     GoalEvaluation(WipGoalEvaluation<I>),
@@ -78,8 +78,7 @@ impl<I: Interner> From<WipCanonicalGoalEvaluationStep<I>> for DebugSolver<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Debug; I: Interner)]
 struct WipGoalEvaluation<I: Interner> {
     pub uncanonicalized_goal: Goal<I, I::Predicate>,
     pub orig_values: Vec<I::GenericArg>,
@@ -96,8 +95,7 @@ impl<I: Interner> WipGoalEvaluation<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""))]
+#[derive_where(PartialEq, Eq; I: Interner)]
 pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<I: Interner> {
     Overflow,
     CycleInStack,
@@ -118,8 +116,7 @@ impl<I: Interner> std::fmt::Debug for WipCanonicalGoalEvaluationKind<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Debug; I: Interner)]
 struct WipCanonicalGoalEvaluation<I: Interner> {
     goal: CanonicalInput<I>,
     kind: Option<WipCanonicalGoalEvaluationKind<I>>,
@@ -153,8 +150,7 @@ impl<I: Interner> WipCanonicalGoalEvaluation<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Debug; I: Interner)]
 struct WipCanonicalGoalEvaluationStep<I: Interner> {
     /// Unlike `EvalCtxt::var_values`, we append a new
     /// generic arg here whenever we create a new inference
@@ -193,8 +189,7 @@ impl<I: Interner> WipCanonicalGoalEvaluationStep<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Debug; I: Interner)]
 struct WipProbe<I: Interner> {
     initial_num_var_values: usize,
     steps: Vec<WipProbeStep<I>>,
@@ -212,8 +207,7 @@ impl<I: Interner> WipProbe<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Debug; I: Interner)]
 enum WipProbeStep<I: Interner> {
     AddGoal(GoalSource, inspect::CanonicalState<I, Goal<I, I::Predicate>>),
     NestedProbe(WipProbe<I>),
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index c79dad3953b..391a5791776 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -53,6 +53,12 @@ parse_bare_cr = {$double_quotes ->
 
 parse_bare_cr_in_raw_string = bare CR not allowed in raw string
 
+parse_binder_and_polarity = `for<...>` binder not allowed with `{$polarity}` trait polarity modifier
+    .label = there is not a well-defined meaning for a higher-ranked `{$polarity}` trait
+
+parse_binder_before_modifiers = `for<...>` binder should be placed before trait bound modifiers
+    .label = place the `for<...>` binder before any modifiers
+
 parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
 
 parse_box_not_pat = expected pattern, found {$descr}
@@ -577,6 +583,9 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl
 parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds
     .suggestion = remove the `{$modifier}`
 
+parse_modifiers_and_polarity = `{$modifiers_concatenated}` trait not allowed with `{$polarity}` trait polarity modifier
+    .label = there is not a well-defined meaning for a `{$modifiers_concatenated} {$polarity}` trait
+
 parse_more_than_one_char = character literal may only contain one codepoint
     .followed_by = this `{$chr}` is followed by the combining {$len ->
         [one] mark
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 109d36fe689..2e81d2a876b 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -3212,3 +3212,33 @@ pub struct UnsafeAttrOutsideUnsafeSuggestion {
     #[suggestion_part(code = ")")]
     pub right: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(parse_binder_before_modifiers)]
+pub struct BinderBeforeModifiers {
+    #[primary_span]
+    pub binder_span: Span,
+    #[label]
+    pub modifiers_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_binder_and_polarity)]
+pub struct BinderAndPolarity {
+    #[primary_span]
+    pub polarity_span: Span,
+    #[label]
+    pub binder_span: Span,
+    pub polarity: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_modifiers_and_polarity)]
+pub struct PolarityAndModifiers {
+    #[primary_span]
+    pub polarity_span: Span,
+    #[label]
+    pub modifiers_span: Span,
+    pub polarity: &'static str,
+    pub modifiers_concatenated: String,
+}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index fbc5b914600..9aaf4b99243 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2773,7 +2773,14 @@ impl<'a> Parser<'a> {
             let snapshot = p.create_snapshot_for_diagnostic();
             let param = p.parse_param_general(req_name, first_param).or_else(|e| {
                 let guar = e.emit();
-                let lo = p.prev_token.span;
+                // When parsing a param failed, we should check to make the span of the param
+                // not contain '(' before it.
+                // For example when parsing `*mut Self` in function `fn oof(*mut Self)`.
+                let lo = if let TokenKind::OpenDelim(Delimiter::Parenthesis) = p.prev_token.kind {
+                    p.prev_token.span.shrink_to_hi()
+                } else {
+                    p.prev_token.span
+                };
                 p.restore_snapshot(snapshot);
                 // Skip every token until next possible arg or end.
                 p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]);
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index a8134110010..f95ecd254ce 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -935,9 +935,14 @@ impl<'a> Parser<'a> {
     /// If no modifiers are present, this does not consume any tokens.
     ///
     /// ```ebnf
-    /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"]
+    /// CONSTNESS = [["~"] "const"]
+    /// ASYNCNESS = ["async"]
+    /// POLARITY = ["?" | "!"]
     /// ```
+    ///
+    /// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
     fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
+        let modifier_lo = self.token.span;
         let constness = if self.eat(&token::Tilde) {
             let tilde = self.prev_token.span;
             self.expect_keyword(kw::Const)?;
@@ -970,6 +975,7 @@ impl<'a> Parser<'a> {
         } else {
             BoundAsyncness::Normal
         };
+        let modifier_hi = self.prev_token.span;
 
         let polarity = if self.eat(&token::Question) {
             BoundPolarity::Maybe(self.prev_token.span)
@@ -980,13 +986,40 @@ impl<'a> Parser<'a> {
             BoundPolarity::Positive
         };
 
+        // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`.
+        match polarity {
+            BoundPolarity::Positive => {
+                // All trait bound modifiers allowed to combine with positive polarity
+            }
+            BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => {
+                match (asyncness, constness) {
+                    (BoundAsyncness::Normal, BoundConstness::Never) => {
+                        // Ok, no modifiers.
+                    }
+                    (_, _) => {
+                        let constness = constness.as_str();
+                        let asyncness = asyncness.as_str();
+                        let glue =
+                            if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" };
+                        let modifiers_concatenated = format!("{constness}{glue}{asyncness}");
+                        self.dcx().emit_err(errors::PolarityAndModifiers {
+                            polarity_span,
+                            polarity: polarity.as_str(),
+                            modifiers_span: modifier_lo.to(modifier_hi),
+                            modifiers_concatenated,
+                        });
+                    }
+                }
+            }
+        }
+
         Ok(TraitBoundModifiers { constness, asyncness, polarity })
     }
 
     /// Parses a type bound according to:
     /// ```ebnf
     /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
-    /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
+    /// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH
     /// ```
     ///
     /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`.
@@ -996,9 +1029,25 @@ impl<'a> Parser<'a> {
         has_parens: bool,
         leading_token: &Token,
     ) -> PResult<'a, GenericBound> {
-        let modifiers = self.parse_trait_bound_modifiers()?;
         let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
 
+        let modifiers_lo = self.token.span;
+        let modifiers = self.parse_trait_bound_modifiers()?;
+        let modifiers_span = modifiers_lo.to(self.prev_token.span);
+
+        if let Some(binder_span) = binder_span {
+            match modifiers.polarity {
+                BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => {
+                    self.dcx().emit_err(errors::BinderAndPolarity {
+                        binder_span,
+                        polarity_span,
+                        polarity: modifiers.polarity.as_str(),
+                    });
+                }
+                BoundPolarity::Positive => {}
+            }
+        }
+
         // Recover erroneous lifetime bound with modifiers or binder.
         // e.g. `T: for<'a> 'a` or `T: ~const 'a`.
         if self.token.is_lifetime() {
@@ -1006,6 +1055,11 @@ impl<'a> Parser<'a> {
             return self.parse_generic_lt_bound(lo, has_parens);
         }
 
+        if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? {
+            lifetime_defs.extend(more_lifetime_defs);
+            self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span });
+        }
+
         let mut path = if self.token.is_keyword(kw::Fn)
             && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
             && let Some(path) = self.recover_path_from_fn()
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index d45ee32a624..dbbf802c920 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -244,22 +244,19 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands });
         }
 
-        let unsupported_options: Vec<&'static str> = [
-            (InlineAsmOptions::MAY_UNWIND, "`may_unwind`"),
-            (InlineAsmOptions::NOMEM, "`nomem`"),
-            (InlineAsmOptions::NOSTACK, "`nostack`"),
-            (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
-            (InlineAsmOptions::PURE, "`pure`"),
-            (InlineAsmOptions::READONLY, "`readonly`"),
-        ]
-        .iter()
-        .filter_map(|&(option, name)| if asm.options.contains(option) { Some(name) } else { None })
-        .collect();
+        let supported_options =
+            InlineAsmOptions::RAW | InlineAsmOptions::NORETURN | InlineAsmOptions::ATT_SYNTAX;
+        let unsupported_options = asm.options.difference(supported_options);
 
         if !unsupported_options.is_empty() {
             self.tcx.dcx().emit_err(NakedFunctionsAsmOptions {
                 span,
-                unsupported_options: unsupported_options.join(", "),
+                unsupported_options: unsupported_options
+                    .human_readable_names()
+                    .into_iter()
+                    .map(|name| format!("`{name}`"))
+                    .collect::<Vec<_>>()
+                    .join(", "),
             });
         }
 
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 5bd4fe04848..39da5e395c4 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -73,7 +73,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
             source_len: _,
             lines: _,
             ref multibyte_chars,
-            ref non_narrow_chars,
             ref normalized_pos,
         } = *self;
 
@@ -98,11 +97,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
             char_pos.hash_stable(hcx, hasher);
         }
 
-        non_narrow_chars.len().hash_stable(hcx, hasher);
-        for &char_pos in non_narrow_chars.iter() {
-            char_pos.hash_stable(hcx, hasher);
-        }
-
         normalized_pos.len().hash_stable(hcx, hasher);
         for &char_pos in normalized_pos.iter() {
             char_pos.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index bf7972e392c..046ae5fc593 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2012,7 +2012,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 )
             } else if ident.name == sym::core {
                 (
-                    format!("maybe a missing crate `{ident}`?"),
+                    format!("you might be missing crate `{ident}`"),
                     Some((
                         vec![(ident.span, "std".to_string())],
                         "try using `std` instead of `core`".to_string(),
@@ -2021,7 +2021,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 )
             } else if self.tcx.sess.is_rust_2015() {
                 (
-                    format!("maybe a missing crate `{ident}`?"),
+                    format!("you might be missing crate `{ident}`"),
                     Some((
                         vec![],
                         format!(
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 83a554fe31d..3fdfe77ead9 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-derivative = "2.2.0"
+derive-where = "1.2.7"
 indexmap = { version = "2.0.0" }
 itoa = "1.0"
 md5 = { package = "md-5", version = "0.10.0" }
diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs
index d9e1ebaf0bc..ba7e0cec5bd 100644
--- a/compiler/rustc_span/src/analyze_source_file.rs
+++ b/compiler/rustc_span/src/analyze_source_file.rs
@@ -1,5 +1,4 @@
 use super::*;
-use unicode_width::UnicodeWidthChar;
 
 #[cfg(test)]
 mod tests;
@@ -9,15 +8,12 @@ mod tests;
 ///
 /// This function will use an SSE2 enhanced implementation if hardware support
 /// is detected at runtime.
-pub fn analyze_source_file(
-    src: &str,
-) -> (Vec<RelativeBytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) {
+pub fn analyze_source_file(src: &str) -> (Vec<RelativeBytePos>, Vec<MultiByteChar>) {
     let mut lines = vec![RelativeBytePos::from_u32(0)];
     let mut multi_byte_chars = vec![];
-    let mut non_narrow_chars = vec![];
 
     // Calls the right implementation, depending on hardware support available.
-    analyze_source_file_dispatch(src, &mut lines, &mut multi_byte_chars, &mut non_narrow_chars);
+    analyze_source_file_dispatch(src, &mut lines, &mut multi_byte_chars);
 
     // The code above optimistically registers a new line *after* each \n
     // it encounters. If that point is already outside the source_file, remove
@@ -30,7 +26,7 @@ pub fn analyze_source_file(
         }
     }
 
-    (lines, multi_byte_chars, non_narrow_chars)
+    (lines, multi_byte_chars)
 }
 
 cfg_match! {
@@ -39,11 +35,10 @@ cfg_match! {
             src: &str,
             lines: &mut Vec<RelativeBytePos>,
             multi_byte_chars: &mut Vec<MultiByteChar>,
-            non_narrow_chars: &mut Vec<NonNarrowChar>,
         ) {
             if is_x86_feature_detected!("sse2") {
                 unsafe {
-                    analyze_source_file_sse2(src, lines, multi_byte_chars, non_narrow_chars);
+                    analyze_source_file_sse2(src, lines, multi_byte_chars);
                 }
             } else {
                 analyze_source_file_generic(
@@ -52,7 +47,6 @@ cfg_match! {
                     RelativeBytePos::from_u32(0),
                     lines,
                     multi_byte_chars,
-                    non_narrow_chars,
                 );
             }
         }
@@ -66,7 +60,6 @@ cfg_match! {
             src: &str,
             lines: &mut Vec<RelativeBytePos>,
             multi_byte_chars: &mut Vec<MultiByteChar>,
-            non_narrow_chars: &mut Vec<NonNarrowChar>,
         ) {
             #[cfg(target_arch = "x86")]
             use std::arch::x86::*;
@@ -159,7 +152,6 @@ cfg_match! {
                     RelativeBytePos::from_usize(scan_start),
                     lines,
                     multi_byte_chars,
-                    non_narrow_chars,
                 );
             }
 
@@ -172,7 +164,6 @@ cfg_match! {
                     RelativeBytePos::from_usize(tail_start),
                     lines,
                     multi_byte_chars,
-                    non_narrow_chars,
                 );
             }
         }
@@ -183,7 +174,6 @@ cfg_match! {
             src: &str,
             lines: &mut Vec<RelativeBytePos>,
             multi_byte_chars: &mut Vec<MultiByteChar>,
-            non_narrow_chars: &mut Vec<NonNarrowChar>,
         ) {
             analyze_source_file_generic(
                 src,
@@ -191,7 +181,6 @@ cfg_match! {
                 RelativeBytePos::from_u32(0),
                 lines,
                 multi_byte_chars,
-                non_narrow_chars,
             );
         }
     }
@@ -205,7 +194,6 @@ fn analyze_source_file_generic(
     output_offset: RelativeBytePos,
     lines: &mut Vec<RelativeBytePos>,
     multi_byte_chars: &mut Vec<MultiByteChar>,
-    non_narrow_chars: &mut Vec<NonNarrowChar>,
 ) -> usize {
     assert!(src.len() >= scan_len);
     let mut i = 0;
@@ -227,16 +215,8 @@ fn analyze_source_file_generic(
 
             let pos = RelativeBytePos::from_usize(i) + output_offset;
 
-            match byte {
-                b'\n' => {
-                    lines.push(pos + RelativeBytePos(1));
-                }
-                b'\t' => {
-                    non_narrow_chars.push(NonNarrowChar::Tab(pos));
-                }
-                _ => {
-                    non_narrow_chars.push(NonNarrowChar::ZeroWidth(pos));
-                }
+            if let b'\n' = byte {
+                lines.push(pos + RelativeBytePos(1));
             }
         } else if byte >= 127 {
             // The slow path:
@@ -252,14 +232,6 @@ fn analyze_source_file_generic(
                 let mbc = MultiByteChar { pos, bytes: char_len as u8 };
                 multi_byte_chars.push(mbc);
             }
-
-            // Assume control characters are zero width.
-            // FIXME: How can we decide between `width` and `width_cjk`?
-            let char_width = UnicodeWidthChar::width(c).unwrap_or(0);
-
-            if char_width != 1 {
-                non_narrow_chars.push(NonNarrowChar::new(pos, char_width));
-            }
         }
 
         i += char_len;
diff --git a/compiler/rustc_span/src/analyze_source_file/tests.rs b/compiler/rustc_span/src/analyze_source_file/tests.rs
index 0c77d080c17..e4a24239d8e 100644
--- a/compiler/rustc_span/src/analyze_source_file/tests.rs
+++ b/compiler/rustc_span/src/analyze_source_file/tests.rs
@@ -4,11 +4,10 @@ macro_rules! test {
     (case: $test_name:ident,
      text: $text:expr,
      lines: $lines:expr,
-     multi_byte_chars: $multi_byte_chars:expr,
-     non_narrow_chars: $non_narrow_chars:expr,) => {
+     multi_byte_chars: $multi_byte_chars:expr,) => {
         #[test]
         fn $test_name() {
-            let (lines, multi_byte_chars, non_narrow_chars) = analyze_source_file($text);
+            let (lines, multi_byte_chars) = analyze_source_file($text);
 
             let expected_lines: Vec<RelativeBytePos> =
                 $lines.into_iter().map(RelativeBytePos).collect();
@@ -21,13 +20,6 @@ macro_rules! test {
                 .collect();
 
             assert_eq!(multi_byte_chars, expected_mbcs);
-
-            let expected_nncs: Vec<NonNarrowChar> = $non_narrow_chars
-                .into_iter()
-                .map(|(pos, width)| NonNarrowChar::new(RelativeBytePos(pos), width))
-                .collect();
-
-            assert_eq!(non_narrow_chars, expected_nncs);
         }
     };
 }
@@ -37,7 +29,6 @@ test!(
     text: "",
     lines: vec![],
     multi_byte_chars: vec![],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -45,7 +36,6 @@ test!(
     text: "a\nc",
     lines: vec![0, 2],
     multi_byte_chars: vec![],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -53,7 +43,6 @@ test!(
     text: "012345678\nabcdef012345678\na",
     lines: vec![0, 10, 26],
     multi_byte_chars: vec![],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -61,7 +50,6 @@ test!(
     text: "01234β789\nbcdef0123456789abcdef",
     lines: vec![0, 11],
     multi_byte_chars: vec![(5, 2)],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -69,7 +57,6 @@ test!(
     text: "01234\u{07}6789\nbcdef0123456789abcdef",
     lines: vec![0, 11],
     multi_byte_chars: vec![],
-    non_narrow_chars: vec![(5, 0)],
 );
 
 test!(
@@ -77,7 +64,6 @@ test!(
     text: "aβc",
     lines: vec![0],
     multi_byte_chars: vec![(1, 2)],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -85,7 +71,6 @@ test!(
     text: "0123456789abcΔf012345β",
     lines: vec![0],
     multi_byte_chars: vec![(13, 2), (22, 2)],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -93,7 +78,6 @@ test!(
     text: "0123456789abcdeΔ123456789abcdef01234",
     lines: vec![0],
     multi_byte_chars: vec![(15, 2)],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -101,7 +85,6 @@ test!(
     text: "0123456789abcdeΔ....",
     lines: vec![0],
     multi_byte_chars: vec![(15, 2)],
-    non_narrow_chars: vec![],
 );
 
 test!(
@@ -109,7 +92,6 @@ test!(
     text: "0\t2",
     lines: vec![0],
     multi_byte_chars: vec![],
-    non_narrow_chars: vec![(1, 4)],
 );
 
 test!(
@@ -117,7 +99,6 @@ test!(
     text: "01\t3456789abcdef01234567\u{07}9",
     lines: vec![0],
     multi_byte_chars: vec![],
-    non_narrow_chars: vec![(2, 4), (24, 0)],
 );
 
 test!(
@@ -125,5 +106,4 @@ test!(
     text: "01\t345\n789abcΔf01234567\u{07}9\nbcΔf",
     lines: vec![0, 7, 27],
     multi_byte_chars: vec![(13, 2), (29, 2)],
-    non_narrow_chars: vec![(2, 4), (24, 0)],
 );
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 266956d63d7..b94f910d4bc 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -38,6 +38,7 @@
 // this crate without this line making `rustc_span` available.
 extern crate self as rustc_span;
 
+use derive_where::derive_where;
 use rustc_data_structures::{outline, AtomicRef};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_serialize::opaque::{FileEncoder, MemDecoder};
@@ -467,18 +468,18 @@ impl FileName {
 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
 /// sent to other threads, but some pieces of performance infra run in a separate thread.
 /// Using `Span` is generally preferred.
-#[derive(Clone, Copy, Hash, PartialEq, Eq, derivative::Derivative)]
-#[derivative(PartialOrd, Ord)]
+#[derive(Clone, Copy, Hash, PartialEq, Eq)]
+#[derive_where(PartialOrd, Ord)]
 pub struct SpanData {
     pub lo: BytePos,
     pub hi: BytePos,
     /// Information about where the macro came from, if this piece of
     /// code was created by a macro expansion.
-    #[derivative(PartialOrd = "ignore", Ord = "ignore")]
+    #[derive_where(skip)]
     // `SyntaxContext` does not implement `Ord`.
     // The other fields are enough to determine in-file order.
     pub ctxt: SyntaxContext,
-    #[derivative(PartialOrd = "ignore", Ord = "ignore")]
+    #[derive_where(skip)]
     // `LocalDefId` does not implement `Ord`.
     // The other fields are enough to determine in-file order.
     pub parent: Option<LocalDefId>,
@@ -1345,68 +1346,6 @@ pub struct MultiByteChar {
     pub bytes: u8,
 }
 
-/// Identifies an offset of a non-narrow character in a `SourceFile`.
-#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
-pub enum NonNarrowChar {
-    /// Represents a zero-width character.
-    ZeroWidth(RelativeBytePos),
-    /// Represents a wide (full-width) character.
-    Wide(RelativeBytePos),
-    /// Represents a tab character, represented visually with a width of 4 characters.
-    Tab(RelativeBytePos),
-}
-
-impl NonNarrowChar {
-    fn new(pos: RelativeBytePos, width: usize) -> Self {
-        match width {
-            0 => NonNarrowChar::ZeroWidth(pos),
-            2 => NonNarrowChar::Wide(pos),
-            4 => NonNarrowChar::Tab(pos),
-            _ => panic!("width {width} given for non-narrow character"),
-        }
-    }
-
-    /// Returns the relative offset of the character in the `SourceFile`.
-    pub fn pos(&self) -> RelativeBytePos {
-        match *self {
-            NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p,
-        }
-    }
-
-    /// Returns the width of the character, 0 (zero-width) or 2 (wide).
-    pub fn width(&self) -> usize {
-        match *self {
-            NonNarrowChar::ZeroWidth(_) => 0,
-            NonNarrowChar::Wide(_) => 2,
-            NonNarrowChar::Tab(_) => 4,
-        }
-    }
-}
-
-impl Add<RelativeBytePos> for NonNarrowChar {
-    type Output = Self;
-
-    fn add(self, rhs: RelativeBytePos) -> Self {
-        match self {
-            NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
-            NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
-            NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
-        }
-    }
-}
-
-impl Sub<RelativeBytePos> for NonNarrowChar {
-    type Output = Self;
-
-    fn sub(self, rhs: RelativeBytePos) -> Self {
-        match self {
-            NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
-            NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
-            NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
-        }
-    }
-}
-
 /// Identifies an offset of a character that was normalized away from `SourceFile`.
 #[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
 pub struct NormalizedPos {
@@ -1581,8 +1520,6 @@ pub struct SourceFile {
     pub lines: FreezeLock<SourceFileLines>,
     /// Locations of multi-byte characters in the source code.
     pub multibyte_chars: Vec<MultiByteChar>,
-    /// Width of characters that are not narrow in the source code.
-    pub non_narrow_chars: Vec<NonNarrowChar>,
     /// Locations of characters removed during normalization.
     pub normalized_pos: Vec<NormalizedPos>,
     /// A hash of the filename & crate-id, used for uniquely identifying source
@@ -1604,7 +1541,6 @@ impl Clone for SourceFile {
             source_len: self.source_len,
             lines: self.lines.clone(),
             multibyte_chars: self.multibyte_chars.clone(),
-            non_narrow_chars: self.non_narrow_chars.clone(),
             normalized_pos: self.normalized_pos.clone(),
             stable_id: self.stable_id,
             cnum: self.cnum,
@@ -1679,7 +1615,6 @@ impl<S: SpanEncoder> Encodable<S> for SourceFile {
         }
 
         self.multibyte_chars.encode(s);
-        self.non_narrow_chars.encode(s);
         self.stable_id.encode(s);
         self.normalized_pos.encode(s);
         self.cnum.encode(s);
@@ -1706,7 +1641,6 @@ impl<D: SpanDecoder> Decodable<D> for SourceFile {
             }
         };
         let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
-        let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
         let stable_id = Decodable::decode(d);
         let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
         let cnum: CrateNum = Decodable::decode(d);
@@ -1721,7 +1655,6 @@ impl<D: SpanDecoder> Decodable<D> for SourceFile {
             external_src: FreezeLock::frozen(ExternalSource::Unneeded),
             lines: FreezeLock::new(lines),
             multibyte_chars,
-            non_narrow_chars,
             normalized_pos,
             stable_id,
             cnum,
@@ -1809,8 +1742,7 @@ impl SourceFile {
         let source_len = src.len();
         let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?;
 
-        let (lines, multibyte_chars, non_narrow_chars) =
-            analyze_source_file::analyze_source_file(&src);
+        let (lines, multibyte_chars) = analyze_source_file::analyze_source_file(&src);
 
         Ok(SourceFile {
             name,
@@ -1821,7 +1753,6 @@ impl SourceFile {
             source_len: RelativeBytePos::from_u32(source_len),
             lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
             multibyte_chars,
-            non_narrow_chars,
             normalized_pos,
             stable_id,
             cnum: LOCAL_CRATE,
@@ -2130,41 +2061,45 @@ impl SourceFile {
         let pos = self.relative_position(pos);
         let (line, col_or_chpos) = self.lookup_file_pos(pos);
         if line > 0 {
-            let col = col_or_chpos;
-            let linebpos = self.lines()[line - 1];
-            let col_display = {
-                let start_width_idx = self
-                    .non_narrow_chars
-                    .binary_search_by_key(&linebpos, |x| x.pos())
-                    .unwrap_or_else(|x| x);
-                let end_width_idx = self
-                    .non_narrow_chars
-                    .binary_search_by_key(&pos, |x| x.pos())
-                    .unwrap_or_else(|x| x);
-                let special_chars = end_width_idx - start_width_idx;
-                let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx]
-                    .iter()
-                    .map(|x| x.width())
-                    .sum();
-                col.0 - special_chars + non_narrow
+            let Some(code) = self.get_line(line - 1) else {
+                // If we don't have the code available, it is ok as a fallback to return the bytepos
+                // instead of the "display" column, which is only used to properly show underlines
+                // in the terminal.
+                // FIXME: we'll want better handling of this in the future for the sake of tools
+                // that want to use the display col instead of byte offsets to modify Rust code, but
+                // that is a problem for another day, the previous code was already incorrect for
+                // both displaying *and* third party tools using the json output naïvely.
+                tracing::info!("couldn't find line {line} {:?}", self.name);
+                return (line, col_or_chpos, col_or_chpos.0);
             };
-            (line, col, col_display)
+            let display_col = code.chars().take(col_or_chpos.0).map(|ch| char_width(ch)).sum();
+            (line, col_or_chpos, display_col)
         } else {
-            let chpos = col_or_chpos;
-            let col_display = {
-                let end_width_idx = self
-                    .non_narrow_chars
-                    .binary_search_by_key(&pos, |x| x.pos())
-                    .unwrap_or_else(|x| x);
-                let non_narrow: usize =
-                    self.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum();
-                chpos.0 - end_width_idx + non_narrow
-            };
-            (0, chpos, col_display)
+            // This is never meant to happen?
+            (0, col_or_chpos, col_or_chpos.0)
         }
     }
 }
 
+pub fn char_width(ch: char) -> usize {
+    // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. For now,
+    // just accept that sometimes the code line will be longer than desired.
+    match ch {
+        '\t' => 4,
+        // Keep the following list in sync with `rustc_errors::emitter::OUTPUT_REPLACEMENTS`. These
+        // are control points that we replace before printing with a visible codepoint for the sake
+        // of being able to point at them with underlines.
+        '\u{0000}' | '\u{0001}' | '\u{0002}' | '\u{0003}' | '\u{0004}' | '\u{0005}'
+        | '\u{0006}' | '\u{0007}' | '\u{0008}' | '\u{000B}' | '\u{000C}' | '\u{000D}'
+        | '\u{000E}' | '\u{000F}' | '\u{0010}' | '\u{0011}' | '\u{0012}' | '\u{0013}'
+        | '\u{0014}' | '\u{0015}' | '\u{0016}' | '\u{0017}' | '\u{0018}' | '\u{0019}'
+        | '\u{001A}' | '\u{001B}' | '\u{001C}' | '\u{001D}' | '\u{001E}' | '\u{001F}'
+        | '\u{007F}' | '\u{202A}' | '\u{202B}' | '\u{202D}' | '\u{202E}' | '\u{2066}'
+        | '\u{2067}' | '\u{2068}' | '\u{202C}' | '\u{2069}' => 1,
+        _ => unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1),
+    }
+}
+
 /// Normalizes the source code and records the normalizations.
 fn normalize_src(src: &mut String) -> Vec<NormalizedPos> {
     let mut normalized_pos = vec![];
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index fb212d67997..14c157a0111 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -330,7 +330,6 @@ impl SourceMap {
         cnum: CrateNum,
         file_local_lines: FreezeLock<SourceFileLines>,
         multibyte_chars: Vec<MultiByteChar>,
-        non_narrow_chars: Vec<NonNarrowChar>,
         normalized_pos: Vec<NormalizedPos>,
         metadata_index: u32,
     ) -> Lrc<SourceFile> {
@@ -348,7 +347,6 @@ impl SourceMap {
             source_len,
             lines: file_local_lines,
             multibyte_chars,
-            non_narrow_chars,
             normalized_pos,
             stable_id,
             cnum,
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index dcb02da3719..0c818b94b85 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -232,7 +232,6 @@ fn t10() {
         source_len,
         lines,
         multibyte_chars,
-        non_narrow_chars,
         normalized_pos,
         stable_id,
         ..
@@ -246,7 +245,6 @@ fn t10() {
         CrateNum::ZERO,
         FreezeLock::new(lines.read().clone()),
         multibyte_chars,
-        non_narrow_chars,
         normalized_pos,
         0,
     );
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 1c6993bdd37..ec19cf27668 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -12,17 +12,16 @@ use super::elaborate;
 
 use crate::infer::TyCtxtInferExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::{self, Obligation, ObligationCause};
+use crate::traits::{util, Obligation, ObligationCause};
 use rustc_errors::FatalError;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitor,
+    self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
+    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, Upcast,
 };
-use rustc_middle::ty::{GenericArg, GenericArgs};
-use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::abi::Abi;
@@ -195,7 +194,13 @@ fn predicates_reference_self(
         .predicates
         .iter()
         .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
-        .filter_map(|predicate| predicate_references_self(tcx, predicate))
+        .filter_map(|(clause, sp)| {
+            // Super predicates cannot allow self projections, since they're
+            // impossible to make into existential bounds without eager resolution
+            // or something.
+            // e.g. `trait A: B<Item = Self::Assoc>`.
+            predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No)
+        })
         .collect()
 }
 
@@ -204,20 +209,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
-        .filter_map(|c| predicate_references_self(tcx, c))
+        .filter_map(|(clause, sp)| {
+            // Item bounds *can* have self projections, since they never get
+            // their self type erased.
+            predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
+        })
         .collect()
 }
 
 fn predicate_references_self<'tcx>(
     tcx: TyCtxt<'tcx>,
-    (predicate, sp): (ty::Clause<'tcx>, Span),
+    trait_def_id: DefId,
+    predicate: ty::Clause<'tcx>,
+    sp: Span,
+    allow_self_projections: AllowSelfProjections,
 ) -> Option<Span> {
-    let self_ty = tcx.types.self_param;
-    let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
     match predicate.kind().skip_binder() {
         ty::ClauseKind::Trait(ref data) => {
             // In the case of a trait predicate, we can skip the "self" type.
-            data.trait_ref.args[1..].iter().any(has_self_ty).then_some(sp)
+            data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
         }
         ty::ClauseKind::Projection(ref data) => {
             // And similarly for projections. This should be redundant with
@@ -235,9 +245,9 @@ fn predicate_references_self<'tcx>(
             //
             // This is ALT2 in issue #56288, see that for discussion of the
             // possible alternatives.
-            data.projection_term.args[1..].iter().any(has_self_ty).then_some(sp)
+            data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
         }
-        ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp),
+        ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
 
         ty::ClauseKind::WellFormed(..)
         | ty::ClauseKind::TypeOutlives(..)
@@ -383,7 +393,12 @@ fn virtual_call_violations_for_method<'tcx>(
     let mut errors = Vec::new();
 
     for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
-        if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
+        if contains_illegal_self_type_reference(
+            tcx,
+            trait_def_id,
+            sig.rebind(input_ty),
+            AllowSelfProjections::Yes,
+        ) {
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
                 kind: hir::TraitItemKind::Fn(sig, _),
                 ..
@@ -396,7 +411,12 @@ fn virtual_call_violations_for_method<'tcx>(
             errors.push(MethodViolationCode::ReferencesSelfInput(span));
         }
     }
-    if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
+    if contains_illegal_self_type_reference(
+        tcx,
+        trait_def_id,
+        sig.output(),
+        AllowSelfProjections::Yes,
+    ) {
         errors.push(MethodViolationCode::ReferencesSelfOutput);
     }
     if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
@@ -482,7 +502,7 @@ fn virtual_call_violations_for_method<'tcx>(
             return false;
         }
 
-        contains_illegal_self_type_reference(tcx, trait_def_id, pred)
+        contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
     }) {
         errors.push(MethodViolationCode::WhereClauseReferencesSelf);
     }
@@ -711,121 +731,181 @@ fn receiver_is_dispatchable<'tcx>(
     infcx.predicate_must_hold_modulo_regions(&obligation)
 }
 
+#[derive(Copy, Clone)]
+enum AllowSelfProjections {
+    Yes,
+    No,
+}
+
+/// This is somewhat subtle. In general, we want to forbid
+/// references to `Self` in the argument and return types,
+/// since the value of `Self` is erased. However, there is one
+/// exception: it is ok to reference `Self` in order to access
+/// an associated type of the current trait, since we retain
+/// the value of those associated types in the object type
+/// itself.
+///
+/// ```rust,ignore (example)
+/// trait SuperTrait {
+///     type X;
+/// }
+///
+/// trait Trait : SuperTrait {
+///     type Y;
+///     fn foo(&self, x: Self) // bad
+///     fn foo(&self) -> Self // bad
+///     fn foo(&self) -> Option<Self> // bad
+///     fn foo(&self) -> Self::Y // OK, desugars to next example
+///     fn foo(&self) -> <Self as Trait>::Y // OK
+///     fn foo(&self) -> Self::X // OK, desugars to next example
+///     fn foo(&self) -> <Self as SuperTrait>::X // OK
+/// }
+/// ```
+///
+/// However, it is not as simple as allowing `Self` in a projected
+/// type, because there are illegal ways to use `Self` as well:
+///
+/// ```rust,ignore (example)
+/// trait Trait : SuperTrait {
+///     ...
+///     fn foo(&self) -> <Self as SomeOtherTrait>::X;
+/// }
+/// ```
+///
+/// Here we will not have the type of `X` recorded in the
+/// object type, and we cannot resolve `Self as SomeOtherTrait`
+/// without knowing what `Self` is.
 fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
     value: T,
+    allow_self_projections: AllowSelfProjections,
 ) -> bool {
-    // This is somewhat subtle. In general, we want to forbid
-    // references to `Self` in the argument and return types,
-    // since the value of `Self` is erased. However, there is one
-    // exception: it is ok to reference `Self` in order to access
-    // an associated type of the current trait, since we retain
-    // the value of those associated types in the object type
-    // itself.
-    //
-    // ```rust
-    // trait SuperTrait {
-    //     type X;
-    // }
-    //
-    // trait Trait : SuperTrait {
-    //     type Y;
-    //     fn foo(&self, x: Self) // bad
-    //     fn foo(&self) -> Self // bad
-    //     fn foo(&self) -> Option<Self> // bad
-    //     fn foo(&self) -> Self::Y // OK, desugars to next example
-    //     fn foo(&self) -> <Self as Trait>::Y // OK
-    //     fn foo(&self) -> Self::X // OK, desugars to next example
-    //     fn foo(&self) -> <Self as SuperTrait>::X // OK
-    // }
-    // ```
-    //
-    // However, it is not as simple as allowing `Self` in a projected
-    // type, because there are illegal ways to use `Self` as well:
-    //
-    // ```rust
-    // trait Trait : SuperTrait {
-    //     ...
-    //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
-    // }
-    // ```
-    //
-    // Here we will not have the type of `X` recorded in the
-    // object type, and we cannot resolve `Self as SomeOtherTrait`
-    // without knowing what `Self` is.
-
-    struct IllegalSelfTypeVisitor<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
-        supertraits: Option<Vec<DefId>>,
-    }
+    value
+        .visit_with(&mut IllegalSelfTypeVisitor {
+            tcx,
+            trait_def_id,
+            supertraits: None,
+            allow_self_projections,
+        })
+        .is_break()
+}
 
-    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
-        type Result = ControlFlow<()>;
+struct IllegalSelfTypeVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
+    allow_self_projections: AllowSelfProjections,
+}
 
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
-            match t.kind() {
-                ty::Param(_) => {
-                    if t == self.tcx.types.self_param {
-                        ControlFlow::Break(())
-                    } else {
-                        ControlFlow::Continue(())
-                    }
-                }
-                ty::Alias(ty::Projection, ref data)
-                    if self.tcx.is_impl_trait_in_trait(data.def_id) =>
-                {
-                    // We'll deny these later in their own pass
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
+    type Result = ControlFlow<()>;
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+        match t.kind() {
+            ty::Param(_) => {
+                if t == self.tcx.types.self_param {
+                    ControlFlow::Break(())
+                } else {
                     ControlFlow::Continue(())
                 }
-                ty::Alias(ty::Projection, ref data) => {
-                    // This is a projected type `<Foo as SomeTrait>::X`.
-
-                    // Compute supertraits of current trait lazily.
-                    if self.supertraits.is_none() {
-                        let trait_ref =
-                            ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
-                        self.supertraits = Some(
-                            traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
-                        );
-                    }
+            }
+            ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
+                // We'll deny these later in their own pass
+                ControlFlow::Continue(())
+            }
+            ty::Alias(ty::Projection, ref data) => {
+                match self.allow_self_projections {
+                    AllowSelfProjections::Yes => {
+                        // This is a projected type `<Foo as SomeTrait>::X`.
+
+                        // Compute supertraits of current trait lazily.
+                        if self.supertraits.is_none() {
+                            self.supertraits = Some(
+                                util::supertraits(
+                                    self.tcx,
+                                    ty::Binder::dummy(ty::TraitRef::identity(
+                                        self.tcx,
+                                        self.trait_def_id,
+                                    )),
+                                )
+                                .map(|trait_ref| {
+                                    self.tcx.erase_regions(
+                                        self.tcx.instantiate_bound_regions_with_erased(trait_ref),
+                                    )
+                                })
+                                .collect(),
+                            );
+                        }
 
-                    // Determine whether the trait reference `Foo as
-                    // SomeTrait` is in fact a supertrait of the
-                    // current trait. In that case, this type is
-                    // legal, because the type `X` will be specified
-                    // in the object type. Note that we can just use
-                    // direct equality here because all of these types
-                    // are part of the formal parameter listing, and
-                    // hence there should be no inference variables.
-                    let is_supertrait_of_current_trait = self
-                        .supertraits
-                        .as_ref()
-                        .unwrap()
-                        .contains(&data.trait_ref(self.tcx).def_id);
-
-                    // only walk contained types if it's not a super trait
-                    if is_supertrait_of_current_trait {
-                        ControlFlow::Continue(())
-                    } else {
-                        t.super_visit_with(self) // POSSIBLY reporting an error
+                        // Determine whether the trait reference `Foo as
+                        // SomeTrait` is in fact a supertrait of the
+                        // current trait. In that case, this type is
+                        // legal, because the type `X` will be specified
+                        // in the object type. Note that we can just use
+                        // direct equality here because all of these types
+                        // are part of the formal parameter listing, and
+                        // hence there should be no inference variables.
+                        let is_supertrait_of_current_trait =
+                            self.supertraits.as_ref().unwrap().contains(
+                                &data.trait_ref(self.tcx).fold_with(
+                                    &mut EraseEscapingBoundRegions {
+                                        tcx: self.tcx,
+                                        binder: ty::INNERMOST,
+                                    },
+                                ),
+                            );
+
+                        // only walk contained types if it's not a super trait
+                        if is_supertrait_of_current_trait {
+                            ControlFlow::Continue(())
+                        } else {
+                            t.super_visit_with(self) // POSSIBLY reporting an error
+                        }
                     }
+                    AllowSelfProjections::No => t.super_visit_with(self),
                 }
-                _ => t.super_visit_with(self), // walk contained types, if any
             }
+            _ => t.super_visit_with(self),
         }
+    }
 
-        fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
-            // Constants can only influence object safety if they are generic and reference `Self`.
-            // This is only possible for unevaluated constants, so we walk these here.
-            self.tcx.expand_abstract_consts(ct).super_visit_with(self)
-        }
+    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
+        // Constants can only influence object safety if they are generic and reference `Self`.
+        // This is only possible for unevaluated constants, so we walk these here.
+        self.tcx.expand_abstract_consts(ct).super_visit_with(self)
     }
+}
 
-    value
-        .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
-        .is_break()
+struct EraseEscapingBoundRegions<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    binder: ty::DebruijnIndex,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+    where
+        T: TypeFoldable<TyCtxt<'tcx>>,
+    {
+        self.binder.shift_in(1);
+        let result = t.super_fold_with(self);
+        self.binder.shift_out(1);
+        result
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReBound(debruijn, _) = *r
+            && debruijn < self.binder
+        {
+            r
+        } else {
+            self.tcx.lifetimes.re_erased
+        }
+    }
 }
 
 pub fn contains_illegal_impl_trait_in_trait<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 1d7a0515044..b96e0c8a977 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1202,6 +1202,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                             false
                         }
                     }
+                } else if tcx.trait_is_auto(trait_ref.def_id) {
+                    tcx.dcx().span_delayed_bug(
+                        tcx.def_span(obligation.predicate.def_id),
+                        "associated types not allowed on auto traits",
+                    );
+                    false
                 } else {
                     bug!("unexpected builtin trait with associated type: {trait_ref:?}")
                 }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 7b6d86d22a5..a2bed61a7ae 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -191,11 +191,22 @@ fn resolve_associated_item<'tcx>(
 
             // Any final impl is required to define all associated items.
             if !leaf_def.item.defaultness(tcx).has_value() {
-                let guard = tcx.dcx().span_delayed_bug(
+                let guar = tcx.dcx().span_delayed_bug(
                     tcx.def_span(leaf_def.item.def_id),
                     "missing value for assoc item in impl",
                 );
-                return Err(guard);
+                return Err(guar);
+            }
+
+            // Make sure that we're projecting to an item that has compatible args.
+            // This may happen if we are resolving an instance before codegen, such
+            // as during inlining. This check is also done in projection.
+            if !tcx.check_args_compatible(leaf_def.item.def_id, args) {
+                let guar = tcx.dcx().span_delayed_bug(
+                    tcx.def_span(leaf_def.item.def_id),
+                    "missing value for assoc item in impl",
+                );
+                return Err(guar);
             }
 
             let args = tcx.erase_regions(args);
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 769e350b835..2750838bbe9 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-derivative = "2.2.0"
+derive-where = "1.2.7"
 indexmap = "2.0.0"
 rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 17b35a2807a..c1f6fb36324 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -3,6 +3,7 @@ use std::hash::Hash;
 use std::marker::PhantomData;
 use std::ops::{ControlFlow, Deref};
 
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 #[cfg(feature = "nightly")]
@@ -25,15 +26,12 @@ use crate::{self as ty, Interner};
 /// e.g., `liberate_late_bound_regions`).
 ///
 /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "T: Clone"),
-    Copy(bound = "T: Copy"),
-    Hash(bound = "T: Hash"),
-    PartialEq(bound = "T: PartialEq"),
-    Eq(bound = "T: Eq"),
-    Debug(bound = "T: Debug")
-)]
+#[derive_where(Clone; I: Interner, T: Clone)]
+#[derive_where(Copy; I: Interner, T: Copy)]
+#[derive_where(Hash; I: Interner, T: Hash)]
+#[derive_where(PartialEq; I: Interner, T: PartialEq)]
+#[derive_where(Eq; I: Interner, T: Eq)]
+#[derive_where(Debug; I: Interner, T: Debug)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct Binder<I: Interner, T> {
     value: T,
@@ -351,21 +349,18 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
 ///
 /// If you don't have anything to `instantiate`, you may be looking for
 /// [`instantiate_identity`](EarlyBinder::instantiate_identity) or [`skip_binder`](EarlyBinder::skip_binder).
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "T: Clone"),
-    Copy(bound = "T: Copy"),
-    PartialEq(bound = "T: PartialEq"),
-    Eq(bound = "T: Eq"),
-    Ord(bound = "T: Ord"),
-    PartialOrd(bound = "T: Ord"),
-    Hash(bound = "T: Hash"),
-    Debug(bound = "T: Debug")
-)]
+#[derive_where(Clone; I: Interner, T: Clone)]
+#[derive_where(Copy; I: Interner, T: Copy)]
+#[derive_where(PartialEq; I: Interner, T: PartialEq)]
+#[derive_where(Eq; I: Interner, T: Eq)]
+#[derive_where(Ord; I: Interner, T: Ord)]
+#[derive_where(PartialOrd; I: Interner, T: Ord)]
+#[derive_where(Hash; I: Interner, T: Hash)]
+#[derive_where(Debug; I: Interner, T: Debug)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub struct EarlyBinder<I: Interner, T> {
     value: T,
-    #[derivative(Debug = "ignore")]
+    #[derive_where(skip(Debug))]
     _tcx: PhantomData<I>,
 }
 
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index a9252711b2b..7e93dc248cc 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -1,3 +1,6 @@
+#![allow(clippy::derived_hash_with_manual_eq)]
+
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
@@ -11,15 +14,12 @@ use crate::{self as ty, Interner, UniverseIndex};
 /// A "canonicalized" type `V` is one where all free inference
 /// variables have been rewritten to "canonical vars". These are
 /// numbered starting from 0 in order of first appearance.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "V: Clone"),
-    Hash(bound = "V: Hash"),
-    PartialEq(bound = "V: PartialEq"),
-    Eq(bound = "V: Eq"),
-    Debug(bound = "V: fmt::Debug"),
-    Copy(bound = "V: Copy")
-)]
+#[derive_where(Clone; I: Interner, V: Clone)]
+#[derive_where(Hash; I: Interner, V: Hash)]
+#[derive_where(PartialEq; I: Interner, V: PartialEq)]
+#[derive_where(Eq; I: Interner, V: Eq)]
+#[derive_where(Debug; I: Interner, V: fmt::Debug)]
+#[derive_where(Copy; I: Interner, V: Copy)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub struct Canonical<I: Interner, V> {
@@ -84,15 +84,7 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
 /// canonical value. This is sufficient information for code to create
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    Debug(bound = ""),
-    Eq(bound = ""),
-    PartialEq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct CanonicalVarInfo<I: Interner> {
@@ -149,8 +141,7 @@ impl<I: Interner> CanonicalVarInfo<I> {
 /// Describes the "kind" of the canonical variable. This is a "kind"
 /// in the type-theory sense of the term -- i.e., a "meta" type system
 /// that analyzes type-like values.
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derive_where(Clone, Copy, Hash, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum CanonicalVarKind<I: Interner> {
@@ -178,6 +169,7 @@ pub enum CanonicalVarKind<I: Interner> {
     PlaceholderConst(I::PlaceholderConst),
 }
 
+// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
 impl<I: Interner> PartialEq for CanonicalVarKind<I> {
     fn eq(&self, other: &Self) -> bool {
         match (self, other) {
@@ -266,15 +258,7 @@ pub enum CanonicalTyVarKind {
 /// vectors with the original values that were replaced by canonical
 /// variables. You will need to supply it later to instantiate the
 /// canonicalized query response.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Hash(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 pub struct CanonicalVarValues<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 1a51c95ecdf..458ffdabe94 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -1,3 +1,6 @@
+#![allow(clippy::derived_hash_with_manual_eq)]
+
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
@@ -10,8 +13,7 @@ use crate::{self as ty, DebruijnIndex, Interner};
 use self::ConstKind::*;
 
 /// Represents a constant in Rust.
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
+#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum ConstKind<I: Interner> {
     /// A const generic parameter.
@@ -43,6 +45,7 @@ pub enum ConstKind<I: Interner> {
     Expr(I::ExprConst),
 }
 
+// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
 impl<I: Interner> PartialEq for ConstKind<I> {
     fn eq(&self, other: &Self) -> bool {
         match (self, other) {
@@ -77,14 +80,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
 }
 
 /// An unevaluated (potentially generic) constant used in the type-system.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct UnevaluatedConst<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs
index 8b59e9a6f48..8a6d37b7d23 100644
--- a/compiler/rustc_type_ir/src/error.rs
+++ b/compiler/rustc_type_ir/src/error.rs
@@ -1,3 +1,4 @@
+use derive_where::derive_where;
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::solve::NoSolution;
@@ -21,14 +22,7 @@ impl<T> ExpectedFound<T> {
 }
 
 // Data structures used in type unification
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic)]
 #[cfg_attr(feature = "nightly", rustc_pass_by_value)]
 pub enum TypeError<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs
index b158f0f5eee..008268c3bff 100644
--- a/compiler/rustc_type_ir/src/generic_arg.rs
+++ b/compiler/rustc_type_ir/src/generic_arg.rs
@@ -1,16 +1,10 @@
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 
 use crate::Interner;
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Debug(bound = ""),
-    Eq(bound = ""),
-    PartialEq(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum GenericArgKind<I: Interner> {
     Lifetime(I::Region),
@@ -18,14 +12,7 @@ pub enum GenericArgKind<I: Interner> {
     Const(I::Const),
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Debug(bound = ""),
-    Eq(bound = ""),
-    PartialEq(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum TermKind<I: Interner> {
     Ty(I::Ty),
diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs
index e5d18fcb3d1..6d61a52723a 100644
--- a/compiler/rustc_type_ir/src/opaque_ty.rs
+++ b/compiler/rustc_type_ir/src/opaque_ty.rs
@@ -1,3 +1,4 @@
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
@@ -5,15 +6,7 @@ use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 use crate::inherent::*;
 use crate::{self as ty, Interner};
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = ""),
-    Copy(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub struct OpaqueTypeKey<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
index eb84f3dd587..2f26a439183 100644
--- a/compiler/rustc_type_ir/src/outlives.rs
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -2,6 +2,7 @@
 //! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
 //! RFC for reference.
 
+use derive_where::derive_where;
 use smallvec::{smallvec, SmallVec};
 
 use crate::data_structures::SsoHashSet;
@@ -9,8 +10,7 @@ use crate::inherent::*;
 use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor};
 use crate::{self as ty, Interner};
 
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""))]
+#[derive_where(Debug; I: Interner)]
 pub enum Component<I: Interner> {
     Region(I::Region),
     Param(I::ParamTy),
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index e03f521c5b1..b30346ffc53 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -1,6 +1,7 @@
 use std::fmt;
 use std::hash::Hash;
 
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
@@ -12,15 +13,12 @@ use crate::visit::TypeVisitableExt as _;
 use crate::{self as ty, Interner};
 
 /// `A: 'region`
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "A: Clone"),
-    Copy(bound = "A: Copy"),
-    Hash(bound = "A: Hash"),
-    PartialEq(bound = "A: PartialEq"),
-    Eq(bound = "A: Eq"),
-    Debug(bound = "A: fmt::Debug")
-)]
+#[derive_where(Clone; I: Interner, A: Clone)]
+#[derive_where(Copy; I: Interner, A: Copy)]
+#[derive_where(Hash; I: Interner, A: Hash)]
+#[derive_where(PartialEq; I: Interner, A: PartialEq)]
+#[derive_where(Eq; I: Interner, A: Eq)]
+#[derive_where(Debug; I: Interner, A: fmt::Debug)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct OutlivesPredicate<I: Interner, A>(pub A, pub I::Region);
@@ -50,14 +48,7 @@ where
 ///
 /// Trait references also appear in object types like `Foo<U>`, but in
 /// that case the `Self` parameter is absent from the generic parameters.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct TraitRef<I: Interner> {
@@ -122,14 +113,7 @@ impl<I: Interner> ty::Binder<I, TraitRef<I>> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct TraitPredicate<I: Interner> {
@@ -243,15 +227,7 @@ impl fmt::Display for PredicatePolarity {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum ExistentialPredicate<I: Interner> {
@@ -296,14 +272,7 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
 /// ```
 /// The generic parameters don't include the erased `Self`, only trait
 /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct ExistentialTraitRef<I: Interner> {
@@ -349,14 +318,7 @@ impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> {
 }
 
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct ExistentialProjection<I: Interner> {
@@ -452,15 +414,7 @@ impl AliasTermKind {
 /// * 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(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct AliasTerm<I: Interner> {
@@ -489,7 +443,7 @@ pub struct AliasTerm<I: Interner> {
     pub def_id: I::DefId,
 
     /// This field exists to prevent the creation of `AliasTerm` without using [`AliasTerm::new_from_args`].
-    #[derivative(Debug = "ignore")]
+    #[derive_where(skip(Debug))]
     _use_alias_term_new_instead: (),
 }
 
@@ -631,14 +585,7 @@ impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> {
 /// equality between arbitrary types. Processing an instance of
 /// Form #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct ProjectionPredicate<I: Interner> {
@@ -706,14 +653,7 @@ impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
 
 /// Used by the new solver. Unlike a `ProjectionPredicate` this can only be
 /// proven by actually normalizing `alias`.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct NormalizesTo<I: Interner> {
@@ -748,15 +688,7 @@ impl<I: Interner> fmt::Debug for NormalizesTo<I> {
 /// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
 /// whether the `a` type is the type that we should label as "expected" when
 /// presenting user diagnostics.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct SubtypePredicate<I: Interner> {
@@ -766,15 +698,7 @@ pub struct SubtypePredicate<I: Interner> {
 }
 
 /// Encodes that we have to coerce *from* the `a` type to the `b` type.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct CoercePredicate<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index b1d0f8d19b3..70b7c29bdfc 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -1,3 +1,6 @@
+#![allow(clippy::derived_hash_with_manual_eq)]
+
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
@@ -7,8 +10,7 @@ use crate::{self as ty, Interner};
 
 /// A clause is something that can appear in where bounds or be inferred
 /// by implied bounds.
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
+#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum ClauseKind<I: Interner> {
@@ -38,6 +40,7 @@ pub enum ClauseKind<I: Interner> {
     ConstEvaluatable(I::Const),
 }
 
+// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
 impl<I: Interner> PartialEq for ClauseKind<I> {
     fn eq(&self, other: &Self) -> bool {
         match (self, other) {
@@ -53,14 +56,7 @@ impl<I: Interner> PartialEq for ClauseKind<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum PredicateKind<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 140c89af147..ef18ef15235 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -1,3 +1,6 @@
+#![allow(clippy::derived_hash_with_manual_eq)]
+
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
@@ -124,8 +127,7 @@ rustc_index::newtype_index! {
 /// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
 /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
+#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
 pub enum RegionKind<I: Interner> {
     /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
@@ -193,6 +195,7 @@ const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
     }
 }
 
+// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
 // This is manually implemented because a derive would require `I: PartialEq`
 impl<I: Interner> PartialEq for RegionKind<I> {
     #[inline]
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index ae840ec0210..9fd3534d1fa 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -1,5 +1,6 @@
 use std::iter;
 
+use derive_where::derive_where;
 use rustc_ast_ir::Mutability;
 use tracing::{instrument, trace};
 
@@ -17,19 +18,11 @@ pub type RelateResult<I, T> = Result<T, TypeError<I>>;
 /// a miscompilation or unsoundness.
 ///
 /// When in doubt, use `VarianceDiagInfo::default()`
-#[derive(derivative::Derivative)]
-#[derivative(
-    Copy(bound = ""),
-    Clone(bound = ""),
-    Debug(bound = ""),
-    Default(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Debug, Default; I: Interner)]
 pub enum VarianceDiagInfo<I: Interner> {
     /// No additional information - this is the default.
     /// We will not add any additional information to error messages.
-    #[derivative(Default)]
+    #[derive_where(default)]
     None,
     /// We switched our variance because a generic argument occurs inside
     /// the invariant generic argument of another type.
diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
index 5ccda931f9c..be4f1069cd1 100644
--- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs
+++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs
@@ -1,10 +1,10 @@
+use derive_where::derive_where;
 use rustc_index::IndexVec;
 
 use super::{AvailableDepth, Cx, StackDepth, StackEntry};
 use crate::data_structures::{HashMap, HashSet};
 
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
+#[derive_where(Debug, Clone, Copy; X: Cx)]
 struct QueryData<X: Cx> {
     result: X::Result,
     proof_tree: X::ProofTree,
@@ -20,8 +20,7 @@ struct Success<X: Cx> {
 /// This contains results whose computation never hit the
 /// recursion limit in `success`, and all results which hit
 /// the recursion limit in `with_overflow`.
-#[derive(derivative::Derivative)]
-#[derivative(Default(bound = ""))]
+#[derive_where(Default; X: Cx)]
 struct CacheEntry<X: Cx> {
     success: Option<Success<X>>,
     /// We have to be careful when caching roots of cycles.
@@ -32,8 +31,7 @@ struct CacheEntry<X: Cx> {
     with_overflow: HashMap<usize, X::Tracked<QueryData<X>>>,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""))]
+#[derive_where(Debug; X: Cx)]
 pub(super) struct CacheData<'a, X: Cx> {
     pub(super) result: X::Result,
     pub(super) proof_tree: X::ProofTree,
@@ -41,11 +39,10 @@ pub(super) struct CacheData<'a, X: Cx> {
     pub(super) encountered_overflow: bool,
     // FIXME: This is currently unused, but impacts the design
     // by requiring a closure for `Cx::with_global_cache`.
+    #[allow(dead_code)]
     pub(super) nested_goals: &'a HashSet<X::Input>,
 }
-
-#[derive(derivative::Derivative)]
-#[derivative(Default(bound = ""))]
+#[derive_where(Default; X: Cx)]
 pub struct GlobalCache<X: Cx> {
     map: HashMap<X::Input, CacheEntry<X>>,
 }
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index c2204becdfd..4abf99b1ded 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -3,6 +3,7 @@ use std::hash::Hash;
 use std::marker::PhantomData;
 use std::mem;
 
+use derive_where::derive_where;
 use rustc_index::{Idx, IndexVec};
 use tracing::debug;
 
@@ -153,8 +154,7 @@ rustc_index::newtype_index! {
     pub struct StackDepth {}
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""))]
+#[derive_where(Debug; X: Cx)]
 struct StackEntry<X: Cx> {
     input: X::Input,
 
@@ -226,8 +226,7 @@ struct DetachedEntry<X: Cx> {
 ///
 /// The provisional cache can theoretically result in changes to the observable behavior,
 /// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs.
-#[derive(derivative::Derivative)]
-#[derivative(Default(bound = ""))]
+#[derive_where(Default; X: Cx)]
 struct ProvisionalCacheEntry<X: Cx> {
     stack_depth: Option<StackDepth>,
     with_inductive_stack: Option<DetachedEntry<X>>,
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index 0733c730064..e25df7a0f60 100644
--- a/compiler/rustc_type_ir/src/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -21,6 +21,7 @@ use crate::solve::{
     CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
 };
 use crate::{Canonical, CanonicalVarValues, Interner};
+use derive_where::derive_where;
 use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -31,15 +32,12 @@ use std::hash::Hash;
 /// This is only ever used as [CanonicalState]. Any type information in proof
 /// trees used mechanically has to be canonicalized as we otherwise leak
 /// inference variables from a nested `InferCtxt`.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "T: Clone"),
-    Copy(bound = "T: Copy"),
-    PartialEq(bound = "T: PartialEq"),
-    Eq(bound = "T: Eq"),
-    Hash(bound = "T: Hash"),
-    Debug(bound = "T: Debug")
-)]
+#[derive_where(Clone; I: Interner, T: Clone)]
+#[derive_where(Copy; I: Interner, T: Copy)]
+#[derive_where(PartialEq; I: Interner, T: PartialEq)]
+#[derive_where(Eq; I: Interner, T: Eq)]
+#[derive_where(Hash; I: Interner, T: Hash)]
+#[derive_where(Debug; I: Interner, T: Debug)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub struct State<I: Interner, T> {
     pub var_values: CanonicalVarValues<I>,
@@ -52,24 +50,21 @@ pub type CanonicalState<I, T> = Canonical<I, State<I, T>>;
 /// for the `CanonicalVarValues` of the canonicalized goal.
 /// We use this to map any [CanonicalState] from the local `InferCtxt`
 /// of the solver query to the `InferCtxt` of the caller.
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))]
+#[derive_where(PartialEq, Eq, Hash; I: Interner)]
 pub struct GoalEvaluation<I: Interner> {
     pub uncanonicalized_goal: Goal<I, I::Predicate>,
     pub orig_values: Vec<I::GenericArg>,
     pub evaluation: CanonicalGoalEvaluation<I>,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
 pub struct CanonicalGoalEvaluation<I: Interner> {
     pub goal: CanonicalInput<I>,
     pub kind: CanonicalGoalEvaluationKind<I>,
     pub result: QueryResult<I>,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
 pub enum CanonicalGoalEvaluationKind<I: Interner> {
     Overflow,
     CycleInStack,
@@ -77,8 +72,7 @@ pub enum CanonicalGoalEvaluationKind<I: Interner> {
     Evaluation { final_revision: I::CanonicalGoalEvaluationStepRef },
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
 pub struct CanonicalGoalEvaluationStep<I: Interner> {
     pub instantiated_goal: QueryInput<I, I::Predicate>,
 
@@ -89,8 +83,7 @@ pub struct CanonicalGoalEvaluationStep<I: Interner> {
 /// A self-contained computation during trait solving. This either
 /// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
 /// of a goal.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))]
+#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
 pub struct Probe<I: Interner> {
     /// What happened inside of this probe in chronological order.
     pub steps: Vec<ProbeStep<I>>,
@@ -98,8 +91,7 @@ pub struct Probe<I: Interner> {
     pub final_state: CanonicalState<I, ()>,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)]
 pub enum ProbeStep<I: Interner> {
     /// We added a goal to the `EvalCtxt` which will get proven
     /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
@@ -121,15 +113,7 @@ pub enum ProbeStep<I: Interner> {
 /// What kind of probe we're in. In case the probe represents a candidate, or
 /// the final result of the current goal - via [ProbeKind::Root] - we also
 /// store the [QueryResult].
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Hash(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub enum ProbeKind<I: Interner> {
     /// The root inference context while proving a goal.
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index 2449ac47db6..444fd01f012 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -3,6 +3,7 @@ pub mod inspect;
 use std::fmt;
 use std::hash::Hash;
 
+use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
@@ -89,15 +90,12 @@ pub struct NoSolution;
 ///
 /// Most of the time the `param_env` contains the `where`-bounds of the function
 /// we're currently typechecking while the `predicate` is some trait bound.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "P: Clone"),
-    Copy(bound = "P: Copy"),
-    Hash(bound = "P: Hash"),
-    PartialEq(bound = "P: PartialEq"),
-    Eq(bound = "P: Eq"),
-    Debug(bound = "P: fmt::Debug")
-)]
+#[derive_where(Clone; I: Interner, P: Clone)]
+#[derive_where(Copy; I: Interner, P: Copy)]
+#[derive_where(Hash; I: Interner, P: Hash)]
+#[derive_where(PartialEq; I: Interner, P: PartialEq)]
+#[derive_where(Eq; I: Interner, P: Eq)]
+#[derive_where(Debug; I: Interner, P: fmt::Debug)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct Goal<I: Interner, P> {
@@ -140,15 +138,12 @@ pub enum GoalSource {
     InstantiateHigherRanked,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = "Goal<I, P>: Clone"),
-    Copy(bound = "Goal<I, P>: Copy"),
-    Hash(bound = "Goal<I, P>: Hash"),
-    PartialEq(bound = "Goal<I, P>: PartialEq"),
-    Eq(bound = "Goal<I, P>: Eq"),
-    Debug(bound = "Goal<I, P>: fmt::Debug")
-)]
+#[derive_where(Clone; I: Interner, Goal<I, P>: Clone)]
+#[derive_where(Copy; I: Interner, Goal<I, P>: Copy)]
+#[derive_where(Hash; I: Interner, Goal<I, P>: Hash)]
+#[derive_where(PartialEq; I: Interner, Goal<I, P>: PartialEq)]
+#[derive_where(Eq; I: Interner, Goal<I, P>: Eq)]
+#[derive_where(Debug; I: Interner, Goal<I, P>: fmt::Debug)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct QueryInput<I: Interner, P> {
@@ -157,15 +152,7 @@ pub struct QueryInput<I: Interner, P> {
 }
 
 /// Opaques that are defined in the inference context before a query is called.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = ""),
-    Default(bound = "")
-)]
+#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct PredefinedOpaquesData<I: Interner> {
@@ -173,15 +160,7 @@ pub struct PredefinedOpaquesData<I: Interner> {
 }
 
 /// Possible ways the given goal can be proven.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 pub enum CandidateSource<I: Interner> {
     /// A user written impl.
     ///
@@ -265,15 +244,7 @@ pub enum BuiltinImplSource {
     TupleUnsizing,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct Response<I: Interner> {
@@ -284,15 +255,7 @@ pub struct Response<I: Interner> {
 }
 
 /// Additional constraints returned on success.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = ""),
-    Default(bound = "")
-)]
+#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct ExternalConstraintsData<I: Interner> {
@@ -301,15 +264,7 @@ pub struct ExternalConstraintsData<I: Interner> {
     pub normalization_nested_goals: NestedNormalizationGoals<I>,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = ""),
-    Default(bound = "")
-)]
+#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);
@@ -386,8 +341,7 @@ impl MaybeCause {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+#[derive_where(PartialEq, Eq, Debug; I: Interner)]
 pub struct CacheData<I: Interner> {
     pub result: QueryResult<I>,
     pub proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 9896425a341..4672904ab73 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -1,3 +1,7 @@
+#![allow(clippy::derived_hash_with_manual_eq)]
+
+use derive_where::derive_where;
+
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
@@ -64,8 +68,7 @@ impl AliasTyKind {
 /// Types written by the user start out as `hir::TyKind` and get
 /// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
 #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
+#[derive_where(Clone, Copy, Hash, Eq; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum TyKind<I: Interner> {
     /// The primitive boolean type. Written as `bool`.
@@ -292,6 +295,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
     }
 }
 
+// FIXME(GrigorenkoPV): consider not implementing PartialEq manually
 // This is manually implemented because a derive would require `I: PartialEq`
 impl<I: Interner> PartialEq for TyKind<I> {
     #[inline]
@@ -414,15 +418,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
 /// * 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(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct AliasTy<I: Interner> {
@@ -451,7 +447,7 @@ pub struct AliasTy<I: Interner> {
     pub def_id: I::DefId,
 
     /// This field exists to prevent the creation of `AliasTy` without using [`AliasTy::new_from_args`].
-    #[derivative(Debug = "ignore")]
+    #[derive_where(skip(Debug))]
     pub(crate) _use_alias_ty_new_instead: (),
 }
 
@@ -942,15 +938,7 @@ impl fmt::Debug for InferTy {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Hash(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub struct TypeAndMut<I: Interner> {
@@ -958,14 +946,7 @@ pub struct TypeAndMut<I: Interner> {
     pub mutbl: Mutability,
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Hash(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 pub struct FnSig<I: Interner> {
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 6c5bbbfd59b..81717ce4a22 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -1,5 +1,6 @@
 use std::ops::ControlFlow;
 
+use derive_where::derive_where;
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::fold::{shift_region, TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -100,15 +101,7 @@ use crate::{self as ty, Interner};
 /// * `GR`: The "return type", which is the type of value returned upon
 ///   completion of the coroutine.
 /// * `GW`: The "coroutine witness".
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 pub struct ClosureArgs<I: Interner> {
     /// Lifetime and type parameters from the enclosing function,
@@ -210,15 +203,7 @@ impl<I: Interner> ClosureArgs<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 pub struct CoroutineClosureArgs<I: Interner> {
     pub args: I::GenericArgs,
@@ -370,15 +355,7 @@ impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub struct CoroutineClosureSignature<I: Interner> {
     pub interior: I::Ty,
@@ -552,15 +529,7 @@ impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
     }
 }
 
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub struct GenSig<I: Interner> {
     pub resume_ty: I::Ty,
@@ -569,15 +538,7 @@ pub struct GenSig<I: Interner> {
 }
 
 /// Similar to `ClosureArgs`; see the above documentation for more.
-#[derive(derivative::Derivative)]
-#[derivative(
-    Clone(bound = ""),
-    Copy(bound = ""),
-    Hash(bound = ""),
-    PartialEq(bound = ""),
-    Eq(bound = ""),
-    Debug(bound = "")
-)]
+#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
 #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
 pub struct CoroutineArgs<I: Interner> {
     pub args: I::GenericArgs,
diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml
index 4ed61152736..2edb3f140d7 100644
--- a/compiler/stable_mir/Cargo.toml
+++ b/compiler/stable_mir/Cargo.toml
@@ -5,3 +5,4 @@ edition = "2021"
 
 [dependencies]
 scoped-tls = "1.0"
+serde = { version = "1.0.125", features = [ "derive" ] }
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
index e1c14fe0b38..c003ec1fbc9 100644
--- a/compiler/stable_mir/src/abi.rs
+++ b/compiler/stable_mir/src/abi.rs
@@ -5,12 +5,13 @@ use crate::target::{MachineInfo, MachineSize as Size};
 use crate::ty::{Align, IndexedVal, Ty, VariantIdx};
 use crate::Error;
 use crate::Opaque;
+use serde::Serialize;
 use std::fmt::{self, Debug};
 use std::num::NonZero;
 use std::ops::RangeInclusive;
 
 /// A function ABI definition.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct FnAbi {
     /// The types of each argument.
     pub args: Vec<ArgAbi>,
@@ -31,7 +32,7 @@ pub struct FnAbi {
 }
 
 /// Information about the ABI of a function's argument, or return value.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct ArgAbi {
     pub ty: Ty,
     pub layout: Layout,
@@ -39,7 +40,7 @@ pub struct ArgAbi {
 }
 
 /// How a function argument should be passed in to the target function.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum PassMode {
     /// Ignore the argument.
     ///
@@ -60,14 +61,14 @@ pub enum PassMode {
 }
 
 /// The layout of a type, alongside the type itself.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct TyAndLayout {
     pub ty: Ty,
     pub layout: Layout,
 }
 
 /// The layout of a type in memory.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct LayoutShape {
     /// The fields location withing the layout
     pub fields: FieldsShape,
@@ -108,7 +109,7 @@ impl LayoutShape {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct Layout(usize);
 
 impl Layout {
@@ -127,7 +128,7 @@ impl IndexedVal for Layout {
 }
 
 /// Describes how the fields of a type are shaped in memory.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum FieldsShape {
     /// Scalar primitives and `!`, which never have fields.
     Primitive,
@@ -177,7 +178,7 @@ impl FieldsShape {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum VariantsShape {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
@@ -196,7 +197,7 @@ pub enum VariantsShape {
     },
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum TagEncoding {
     /// The tag directly stores the discriminant, but possibly with a smaller layout
     /// (so converting the tag to the discriminant can require sign extension).
@@ -221,7 +222,7 @@ pub enum TagEncoding {
 
 /// Describes how values of the type are passed by target ABIs,
 /// in terms of categories of C types there are ABI rules for.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum ValueAbi {
     Uninhabited,
     Scalar(Scalar),
@@ -250,7 +251,7 @@ impl ValueAbi {
 }
 
 /// Information about one scalar component of a Rust type.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)]
 pub enum Scalar {
     Initialized {
         /// The primitive type used to represent this value.
@@ -280,7 +281,7 @@ impl Scalar {
 }
 
 /// Fundamental unit of memory access and layout.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)]
 pub enum Primitive {
     /// The `bool` is the signedness of the `Integer` type.
     ///
@@ -310,7 +311,7 @@ impl Primitive {
 }
 
 /// Enum representing the existing integer lengths.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
 pub enum IntegerLength {
     I8,
     I16,
@@ -320,7 +321,7 @@ pub enum IntegerLength {
 }
 
 /// Enum representing the existing float lengths.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
 pub enum FloatLength {
     F16,
     F32,
@@ -354,7 +355,7 @@ impl FloatLength {
 /// An identifier that specifies the address space that some operation
 /// should operate on. Special address spaces have an effect on code generation,
 /// depending on the target and the address spaces it implements.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
 pub struct AddressSpace(pub u32);
 
 impl AddressSpace {
@@ -369,7 +370,7 @@ impl AddressSpace {
 /// sequence:
 ///
 ///    254 (-2), 255 (-1), 0, 1, 2
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
 pub struct WrappingRange {
     pub start: u128,
     pub end: u128,
@@ -420,7 +421,7 @@ impl Debug for WrappingRange {
 }
 
 /// General language calling conventions.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum CallConvention {
     C,
     Rust,
diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs
index d9b987c28a2..bf2b35bf875 100644
--- a/compiler/stable_mir/src/crate_def.rs
+++ b/compiler/stable_mir/src/crate_def.rs
@@ -3,9 +3,10 @@
 
 use crate::ty::{GenericArgs, Span, Ty};
 use crate::{with, Crate, Symbol};
+use serde::Serialize;
 
 /// A unique identification number for each item accessible for the current compilation unit.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
 pub struct DefId(pub(crate) usize);
 
 /// A trait for retrieving information about a particular definition.
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 8385856ae53..fe745326d81 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -27,6 +27,7 @@ pub use crate::error::*;
 use crate::mir::Body;
 use crate::mir::Mutability;
 use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
+use serde::Serialize;
 
 pub mod abi;
 #[macro_use]
@@ -74,7 +75,7 @@ pub type TraitDecls = Vec<TraitDef>;
 pub type ImplTraitDecls = Vec<ImplDef>;
 
 /// Holds information about a crate.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
 pub struct Crate {
     pub id: CrateNum,
     pub name: Symbol,
@@ -98,7 +99,7 @@ impl Crate {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
 pub enum ItemKind {
     Fn,
     Static,
@@ -106,7 +107,7 @@ pub enum ItemKind {
     Ctor(CtorKind),
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
 pub enum CtorKind {
     Const,
     Fn,
@@ -116,6 +117,7 @@ pub type Filename = String;
 
 crate_def_with_ty! {
     /// Holds information about an item in a crate.
+    #[derive(Serialize)]
     pub CrateItem;
 }
 
@@ -188,7 +190,7 @@ pub fn all_trait_impls() -> ImplTraitDecls {
 }
 
 /// A type that provides internal information but that can still be used for debug purpose.
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash, Serialize)]
 pub struct Opaque(String);
 
 impl std::fmt::Display for Opaque {
diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs
index ef1568151f2..9e0cac67f0a 100644
--- a/compiler/stable_mir/src/mir/alloc.rs
+++ b/compiler/stable_mir/src/mir/alloc.rs
@@ -4,11 +4,12 @@ use crate::mir::mono::{Instance, StaticDef};
 use crate::target::{Endian, MachineInfo};
 use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
 use crate::{with, Error};
+use serde::Serialize;
 use std::io::Read;
 
 /// An allocation in the SMIR global memory can be either a function pointer,
 /// a static, or a "real" allocation with some data in it.
-#[derive(Debug, Clone, Eq, PartialEq)]
+#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
 pub enum GlobalAlloc {
     /// The alloc ID is used as a function pointer.
     Function(Instance),
@@ -41,7 +42,7 @@ impl GlobalAlloc {
 }
 
 /// A unique identification number for each provenance
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
 pub struct AllocId(usize);
 
 impl IndexedVal for AllocId {
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index e0f9e7ae67a..f7457ecd38f 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -5,10 +5,11 @@ use crate::ty::{
     TyConst, TyKind, VariantIdx,
 };
 use crate::{Error, Opaque, Span, Symbol};
+use serde::Serialize;
 use std::io;
 
 /// The SMIR representation of a single function.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Serialize)]
 pub struct Body {
     pub blocks: Vec<BasicBlock>,
 
@@ -104,20 +105,20 @@ impl Body {
 
 type LocalDecls = Vec<LocalDecl>;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct LocalDecl {
     pub ty: Ty,
     pub span: Span,
     pub mutability: Mutability,
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
 pub struct BasicBlock {
     pub statements: Vec<Statement>,
     pub terminator: Terminator,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct Terminator {
     pub kind: TerminatorKind,
     pub span: Span,
@@ -131,7 +132,7 @@ impl Terminator {
 
 pub type Successors = Vec<BasicBlockIdx>;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum TerminatorKind {
     Goto {
         target: BasicBlockIdx,
@@ -221,7 +222,7 @@ impl TerminatorKind {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct InlineAsmOperand {
     pub in_value: Option<Operand>,
     pub out_place: Option<Place>,
@@ -230,7 +231,7 @@ pub struct InlineAsmOperand {
     pub raw_rpr: String,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum UnwindAction {
     Continue,
     Unreachable,
@@ -238,7 +239,7 @@ pub enum UnwindAction {
     Cleanup(BasicBlockIdx),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum AssertMessage {
     BoundsCheck { len: Operand, index: Operand },
     Overflow(BinOp, Operand, Operand),
@@ -307,7 +308,7 @@ impl AssertMessage {
     }
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum BinOp {
     Add,
     AddUnchecked,
@@ -342,7 +343,7 @@ impl BinOp {
     }
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum UnOp {
     Not,
     Neg,
@@ -357,20 +358,20 @@ impl UnOp {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum CoroutineKind {
     Desugared(CoroutineDesugaring, CoroutineSource),
     Coroutine(Movability),
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum CoroutineSource {
     Block,
     Closure,
     Fn,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum CoroutineDesugaring {
     Async,
 
@@ -386,7 +387,7 @@ pub(crate) type LocalDefId = Opaque;
 pub(crate) type Coverage = Opaque;
 
 /// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum FakeReadCause {
     ForMatchGuard,
     ForMatchedPlace(LocalDefId),
@@ -396,7 +397,7 @@ pub enum FakeReadCause {
 }
 
 /// Describes what kind of retag is to be performed
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
 pub enum RetagKind {
     FnEntry,
     TwoPhase,
@@ -404,7 +405,7 @@ pub enum RetagKind {
     Default,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
 pub enum Variance {
     Covariant,
     Invariant,
@@ -412,26 +413,26 @@ pub enum Variance {
     Bivariant,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct CopyNonOverlapping {
     pub src: Operand,
     pub dst: Operand,
     pub count: Operand,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum NonDivergingIntrinsic {
     Assume(Operand),
     CopyNonOverlapping(CopyNonOverlapping),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct Statement {
     pub kind: StatementKind,
     pub span: Span,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum StatementKind {
     Assign(Place, Rvalue),
     FakeRead(FakeReadCause, Place),
@@ -448,7 +449,7 @@ pub enum StatementKind {
     Nop,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum Rvalue {
     /// Creates a pointer with the indicated mutability to the place.
     ///
@@ -622,7 +623,7 @@ impl Rvalue {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum AggregateKind {
     Array(Ty),
     Tuple,
@@ -633,14 +634,14 @@ pub enum AggregateKind {
     RawPtr(Ty, Mutability),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum Operand {
     Copy(Place),
     Move(Place),
     Constant(ConstOperand),
 }
 
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Clone, Eq, PartialEq, Serialize)]
 pub struct Place {
     pub local: Local,
     /// projection out of a place (access a field, deref a pointer, etc)
@@ -653,7 +654,7 @@ impl From<Local> for Place {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct ConstOperand {
     pub span: Span,
     pub user_ty: Option<UserTypeAnnotationIndex>,
@@ -661,7 +662,7 @@ pub struct ConstOperand {
 }
 
 /// Debug information pertaining to a user variable.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct VarDebugInfo {
     /// The variable name.
     pub name: Symbol,
@@ -703,19 +704,19 @@ impl VarDebugInfo {
 
 pub type SourceScope = u32;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct SourceInfo {
     pub span: Span,
     pub scope: SourceScope,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct VarDebugInfoFragment {
     pub ty: Ty,
     pub projection: Vec<ProjectionElem>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum VarDebugInfoContents {
     Place(Place),
     Const(ConstOperand),
@@ -726,7 +727,7 @@ pub enum VarDebugInfoContents {
 // ProjectionElem<Local, Ty>) and user-provided type annotations (for which the projection elements
 // are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use
 // ProjectionElem for Places.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ProjectionElem {
     /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place.
     Deref,
@@ -800,7 +801,7 @@ pub enum ProjectionElem {
     Subtype(Ty),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct UserTypeProjection {
     pub base: UserTypeAnnotationIndex,
 
@@ -830,7 +831,7 @@ pub type FieldIdx = usize;
 type UserTypeAnnotationIndex = usize;
 
 /// The possible branch sites of a [TerminatorKind::SwitchInt].
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct SwitchTargets {
     /// The conditional branches where the first element represents the value that guards this
     /// branch, and the second element is the branch target.
@@ -867,7 +868,7 @@ impl SwitchTargets {
     }
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     Shared,
@@ -894,14 +895,14 @@ impl BorrowKind {
     }
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum MutBorrowKind {
     Default,
     TwoPhaseBorrow,
     ClosureCapture,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum FakeBorrowKind {
     /// A shared (deep) borrow. Data must be immutable and is aliasable.
     Deep,
@@ -912,19 +913,19 @@ pub enum FakeBorrowKind {
     Shallow,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum Mutability {
     Not,
     Mut,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum Safety {
     Safe,
     Unsafe,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum PointerCoercion {
     /// Go from a fn-item type to a fn-pointer type.
     ReifyFnPointer,
@@ -951,7 +952,7 @@ pub enum PointerCoercion {
     Unsize,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum CastKind {
     // FIXME(smir-rename): rename this to PointerExposeProvenance
     PointerExposeAddress,
@@ -967,7 +968,7 @@ pub enum CastKind {
     Transmute,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum NullOp {
     /// Returns the size of a value of that type.
     SizeOf,
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 572f1499c5a..c23293388f9 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -3,17 +3,18 @@ use crate::crate_def::CrateDef;
 use crate::mir::Body;
 use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
 use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
+use serde::Serialize;
 use std::fmt::{Debug, Formatter};
 use std::io;
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum MonoItem {
     Fn(Instance),
     Static(StaticDef),
     GlobalAsm(Opaque),
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)]
 pub struct Instance {
     /// The type of instance.
     pub kind: InstanceKind,
@@ -22,7 +23,7 @@ pub struct Instance {
     pub def: InstanceDef,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
 pub enum InstanceKind {
     /// A user defined item.
     Item,
@@ -240,7 +241,7 @@ impl From<StaticDef> for CrateItem {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct InstanceDef(usize);
 
 impl CrateDef for InstanceDef {
@@ -251,6 +252,7 @@ impl CrateDef for InstanceDef {
 
 crate_def! {
     /// Holds information about a static variable definition.
+    #[derive(Serialize)]
     pub StaticDef;
 }
 
diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs
index e00a418c540..9fb5e046abc 100644
--- a/compiler/stable_mir/src/target.rs
+++ b/compiler/stable_mir/src/target.rs
@@ -1,9 +1,10 @@
 //! Provide information about the machine that this is being compiled into.
 
 use crate::compiler_interface::with;
+use serde::Serialize;
 
 /// The properties of the target machine being compiled into.
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Serialize)]
 pub struct MachineInfo {
     pub endian: Endian,
     pub pointer_width: MachineSize,
@@ -23,14 +24,14 @@ impl MachineInfo {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Serialize)]
 pub enum Endian {
     Little,
     Big,
 }
 
 /// Represent the size of a component.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
 pub struct MachineSize {
     num_bits: usize,
 }
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 9b912d16074..fb0b8f4d0c3 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -8,10 +8,11 @@ use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
 use crate::mir::mono::StaticDef;
 use crate::target::MachineInfo;
 use crate::{Filename, Opaque};
+use serde::Serialize;
 use std::fmt::{self, Debug, Display, Formatter};
 use std::ops::Range;
 
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)]
 pub struct Ty(usize);
 
 impl Debug for Ty {
@@ -100,13 +101,13 @@ impl Ty {
 }
 
 /// Represents a pattern in the type system
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum Pattern {
     Range { start: Option<TyConst>, end: Option<TyConst>, include_end: bool },
 }
 
 /// Represents a constant in the type system
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct TyConst {
     pub(crate) kind: TyConstKind,
     pub id: TyConstId,
@@ -133,7 +134,7 @@ impl TyConst {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum TyConstKind {
     Param(ParamConst),
     Bound(DebruijnIndex, BoundVar),
@@ -144,11 +145,11 @@ pub enum TyConstKind {
     ZSTValue(Ty),
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct TyConstId(usize);
 
 /// Represents a constant in MIR
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct MirConst {
     /// The constant kind.
     pub(crate) kind: ConstantKind,
@@ -205,17 +206,17 @@ impl MirConst {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
 pub struct MirConstId(usize);
 
 type Ident = Opaque;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct Region {
     pub kind: RegionKind,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum RegionKind {
     ReEarlyParam(EarlyParamRegion),
     ReBound(DebruijnIndex, BoundRegion),
@@ -226,7 +227,7 @@ pub enum RegionKind {
 
 pub(crate) type DebruijnIndex = u32;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct EarlyParamRegion {
     pub index: u32,
     pub name: Symbol,
@@ -234,7 +235,7 @@ pub struct EarlyParamRegion {
 
 pub(crate) type BoundVar = u32;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct BoundRegion {
     pub var: BoundVar,
     pub kind: BoundRegionKind,
@@ -242,13 +243,13 @@ pub struct BoundRegion {
 
 pub(crate) type UniverseIndex = u32;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct Placeholder<T> {
     pub universe: UniverseIndex,
     pub bound: T,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Serialize)]
 pub struct Span(usize);
 
 impl Debug for Span {
@@ -272,7 +273,7 @@ impl Span {
     }
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Serialize)]
 /// Information you get from `Span` in a struct form.
 /// Line and col start from 1.
 pub struct LineInfo {
@@ -282,7 +283,7 @@ pub struct LineInfo {
     pub end_col: usize,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum TyKind {
     RigidTy(RigidTy),
     Alias(AliasKind, AliasTy),
@@ -521,7 +522,7 @@ pub struct TypeAndMut {
     pub mutability: Mutability,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum RigidTy {
     Bool,
     Char,
@@ -560,7 +561,7 @@ impl From<RigidTy> for TyKind {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
 pub enum IntTy {
     Isize,
     I8,
@@ -583,7 +584,7 @@ impl IntTy {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
 pub enum UintTy {
     Usize,
     U8,
@@ -606,7 +607,7 @@ impl UintTy {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
 pub enum FloatTy {
     F16,
     F32,
@@ -614,13 +615,14 @@ pub enum FloatTy {
     F128,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
 pub enum Movability {
     Static,
     Movable,
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub ForeignModuleDef;
 }
 
@@ -643,6 +645,7 @@ impl ForeignModule {
 
 crate_def_with_ty! {
     /// Hold information about a ForeignItem in a crate.
+    #[derive(Serialize)]
     pub ForeignDef;
 }
 
@@ -652,7 +655,7 @@ impl ForeignDef {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
 pub enum ForeignItemKind {
     Fn(FnDef),
     Static(StaticDef),
@@ -661,6 +664,7 @@ pub enum ForeignItemKind {
 
 crate_def_with_ty! {
     /// Hold information about a function definition in a crate.
+    #[derive(Serialize)]
     pub FnDef;
 }
 
@@ -694,6 +698,7 @@ impl FnDef {
 }
 
 crate_def_with_ty! {
+    #[derive(Serialize)]
     pub IntrinsicDef;
 }
 
@@ -718,26 +723,31 @@ impl From<IntrinsicDef> for FnDef {
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub ClosureDef;
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub CoroutineDef;
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub ParamDef;
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub BrNamedDef;
 }
 
-crate_def_with_ty! {
+crate_def! {
+    #[derive(Serialize)]
     pub AdtDef;
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
 pub enum AdtKind {
     Enum,
     Union,
@@ -791,7 +801,7 @@ impl AdtDef {
 }
 
 /// Definition of a variant, which can be either a struct / union field or an enum variant.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct VariantDef {
     /// The variant index.
     ///
@@ -820,7 +830,7 @@ impl VariantDef {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct FieldDef {
     /// The field definition.
     ///
@@ -871,11 +881,13 @@ impl AdtKind {
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub AliasDef;
 }
 
 crate_def! {
     /// A trait's definition.
+    #[derive(Serialize)]
     pub TraitDef;
 }
 
@@ -886,15 +898,18 @@ impl TraitDef {
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub GenericDef;
 }
 
 crate_def_with_ty! {
+    #[derive(Serialize)]
     pub ConstDef;
 }
 
 crate_def! {
     /// A trait impl definition.
+    #[derive(Serialize)]
     pub ImplDef;
 }
 
@@ -906,15 +921,17 @@ impl ImplDef {
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub RegionDef;
 }
 
 crate_def! {
+    #[derive(Serialize)]
     pub CoroutineWitnessDef;
 }
 
 /// A list of generic arguments.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct GenericArgs(pub Vec<GenericArgKind>);
 
 impl std::ops::Index<ParamTy> for GenericArgs {
@@ -933,7 +950,7 @@ impl std::ops::Index<ParamConst> for GenericArgs {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum GenericArgKind {
     Lifetime(Region),
     Type(Ty),
@@ -970,13 +987,13 @@ impl GenericArgKind {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum TermKind {
     Type(Ty),
     Const(TyConst),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum AliasKind {
     Projection,
     Inherent,
@@ -984,13 +1001,13 @@ pub enum AliasKind {
     Weak,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct AliasTy {
     pub def_id: AliasDef,
     pub args: GenericArgs,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct AliasTerm {
     pub def_id: AliasDef,
     pub args: GenericArgs,
@@ -1008,7 +1025,7 @@ impl PolyFnSig {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct FnSig {
     pub inputs_and_output: Vec<Ty>,
     pub c_variadic: bool,
@@ -1026,7 +1043,7 @@ impl FnSig {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
 pub enum Abi {
     Rust,
     C { unwind: bool },
@@ -1055,7 +1072,7 @@ pub enum Abi {
 }
 
 /// A binder represents a possibly generic type and its bound vars.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct Binder<T> {
     pub value: T,
     pub bound_vars: Vec<BoundVariableKind>,
@@ -1095,38 +1112,38 @@ impl<T> Binder<T> {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct EarlyBinder<T> {
     pub value: T,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum BoundVariableKind {
     Ty(BoundTyKind),
     Region(BoundRegionKind),
     Const,
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
 pub enum BoundTyKind {
     Anon,
     Param(ParamDef, String),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum BoundRegionKind {
     BrAnon,
     BrNamed(BrNamedDef, String),
     BrEnv,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum DynKind {
     Dyn,
     DynStar,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ExistentialPredicate {
     Trait(ExistentialTraitRef),
     Projection(ExistentialProjection),
@@ -1136,7 +1153,7 @@ pub enum ExistentialPredicate {
 /// An existential reference to a trait where `Self` is not included.
 ///
 /// The `generic_args` will include any other known argument.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct ExistentialTraitRef {
     pub def_id: TraitDef,
     pub generic_args: GenericArgs,
@@ -1154,20 +1171,20 @@ impl ExistentialTraitRef {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct ExistentialProjection {
     pub def_id: TraitDef,
     pub generic_args: GenericArgs,
     pub term: TermKind,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct ParamTy {
     pub index: u32,
     pub name: String,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct BoundTy {
     pub var: usize,
     pub kind: BoundTyKind,
@@ -1178,7 +1195,7 @@ pub type Bytes = Vec<Option<u8>>;
 /// Size in bytes.
 pub type Size = usize;
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
 pub struct Prov(pub AllocId);
 
 pub type Align = u64;
@@ -1186,14 +1203,14 @@ pub type Promoted = u32;
 pub type InitMaskMaterialized = Vec<u64>;
 
 /// Stores the provenance information of pointers stored in memory.
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
 pub struct ProvenanceMap {
     /// Provenance in this map applies from the given offset for an entire pointer-size worth of
     /// bytes. Two entries in this map are always at least a pointer size apart.
     pub ptrs: Vec<(Size, Prov)>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
 pub struct Allocation {
     pub bytes: Bytes,
     pub provenance: ProvenanceMap,
@@ -1269,7 +1286,7 @@ impl Allocation {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ConstantKind {
     Ty(TyConst),
     Allocated(Allocation),
@@ -1280,27 +1297,27 @@ pub enum ConstantKind {
     ZeroSized,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct ParamConst {
     pub index: u32,
     pub name: String,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct UnevaluatedConst {
     pub def: ConstDef,
     pub args: GenericArgs,
     pub promoted: Option<Promoted>,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
 pub enum TraitSpecializationKind {
     None,
     Marker,
     AlwaysApplicable,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct TraitDecl {
     pub def_id: TraitDef,
     pub safety: Safety,
@@ -1333,7 +1350,7 @@ impl TraitDecl {
 pub type ImplTrait = EarlyBinder<TraitRef>;
 
 /// A complete reference to a trait, i.e., one where `Self` is known.
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct TraitRef {
     pub def_id: TraitDef,
     /// The generic arguments for this definition.
@@ -1367,7 +1384,7 @@ impl TraitRef {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct Generics {
     pub parent: Option<GenericDef>,
     pub parent_count: usize,
@@ -1378,14 +1395,14 @@ pub struct Generics {
     pub host_effect_index: Option<usize>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum GenericParamDefKind {
     Lifetime,
     Type { has_default: bool, synthetic: bool },
     Const { has_default: bool },
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct GenericParamDef {
     pub name: super::Symbol,
     pub def_id: GenericDef,
@@ -1399,7 +1416,7 @@ pub struct GenericPredicates {
     pub predicates: Vec<(PredicateKind, Span)>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum PredicateKind {
     Clause(ClauseKind),
     ObjectSafe(TraitDef),
@@ -1410,7 +1427,7 @@ pub enum PredicateKind {
     AliasRelate(TermKind, TermKind, AliasRelationDirection),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ClauseKind {
     Trait(TraitPredicate),
     RegionOutlives(RegionOutlivesPredicate),
@@ -1421,57 +1438,57 @@ pub enum ClauseKind {
     ConstEvaluatable(TyConst),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ClosureKind {
     Fn,
     FnMut,
     FnOnce,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct SubtypePredicate {
     pub a: Ty,
     pub b: Ty,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct CoercePredicate {
     pub a: Ty,
     pub b: Ty,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum AliasRelationDirection {
     Equate,
     Subtype,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct TraitPredicate {
     pub trait_ref: TraitRef,
     pub polarity: PredicatePolarity,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct OutlivesPredicate<A, B>(pub A, pub B);
 
 pub type RegionOutlivesPredicate = OutlivesPredicate<Region, Region>;
 pub type TypeOutlivesPredicate = OutlivesPredicate<Ty, Region>;
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub struct ProjectionPredicate {
     pub projection_term: AliasTerm,
     pub term: TermKind,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ImplPolarity {
     Positive,
     Negative,
     Reservation,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum PredicatePolarity {
     Positive,
     Negative,
@@ -1514,7 +1531,7 @@ index_impl!(Span);
 /// `a` is in the variant with the `VariantIdx` of `0`,
 /// `c` is in the variant with the `VariantIdx` of `1`, and
 /// `g` is in the variant with the `VariantIdx` of `0`.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
 pub struct VariantIdx(usize);
 
 index_impl!(VariantIdx);